cucumber-attic / gherkin

Cross platform parser for the Gherkin language. Used by Cucumber to parse .feature files.
252 stars 127 forks source link

Compiler design and pickles #12

Closed aslakhellesoy closed 8 years ago

aslakhellesoy commented 9 years ago

Let's use this issue to discuss how to design the Gherkin compiler, which is described at a very high level in the toplevel README. My goal is to decouple Cucumber implementations from Gherkin so Cucumber implementations can consume other formats.

I've been playing around with various designs to implement the compiler - both a visitable AST and a plain old external iteration one. I'm currently leaning towards a non-visitor one because I think a visitable one adds unnecessary complexity.

IMO visitor is only really useful when there is a high degree of polymorphism in the child nodes. In the Gherkin AST it's only Scenario|ScenarioOutline and DataTable|DocString that are polymorphic.

If we stick with visitor we have to decide where to put iteration - in the nodes or in the visitor. For the compiler I think a depth-first traversal is best. For pretty-printing I think a breadth-first traversal is best. In other words, if we implement iteration in the nodes we can't please everyone (unless we introduce a pluggable tree walker).

Furthermore, I'd like all implementations to be as similar as possible. The JavaScript implementation doesn't even define types for the AST (they are just dumb objects with properties). I love the simplicity of that and I'd be sad to have to complicate it.

My current feeling is to not use visitor at all, and let the compiler traverse the AST entirely on its own, using external iteration. It's not as elegant perhaps, but it's more pragmatic IMO.

The next question is - what does the compiler produce? My idea is that it produces pickles! More specifically a list of PickledCase (compiled scenarios). This is a struct that is completely decoupled from the Gherkin AST - it only has a source array with Location to produce a stack trace.

The pickles would eventually move to a separate repo/library, and Cucumber implementations will only depend on pickles for the runtime. This would enable is to come up with alternative formats for Cucumber, such as Markdown or even Excel. Just write another parser/compiler that produces pickles.

Let me know what you think. /cc @gasparnagy @muhqu @jbpros @tooky @mattwynne @everzet @stof

sebrose commented 9 years ago

There's already an OSS project called Pickles in the Cucumber/Specflow space.

Are you happy overloading that name?

On 1 Apr 2015, at 12:14, Aslak Hellesøy notifications@github.com wrote:

Let's use this issue to discuss how to design the Gherkin compiler, which is described at a very high level in the toplevel README. My goal is to decouple Cucumber implementations from Gherkin so Cucumber implementations can consume other formats.

I've been playing around with various designs to implement the compiler - both a visitable AST and a plain old external iteration one. I'm currently leaning towards a non-visitor one because I think a visitable one adds unnecessary complexity.

IMO visitor is only really useful when there is a high degree of polymorphism in the child nodes. In the Gherkin AST it's only Scenario|ScenarioOutline and DataTable|DocString that are polymorphic.

If we stick with visitor we have to decide where to put iteration - in the nodes or in the visitor. For the compiler I think a depth-first traversal is best. For pretty-printing I think a breadth-first traversal is best. In other words, if we implement iteration in the nodes we can't please everyone (unless we introduce a pluggable tree walker).

Furthermore, I'd like all implementations to be as similar as possible. The JavaScript implementation doesn't even define types for the AST (they are just dumb objects with properties). I love the simplicity of that and I'd be sad to have to complicate it.

My current feeling is to not use visitor at all, and let the compiler traverse the AST entirely on its own, using external iteration. It's not as elegant perhaps, but it's more pragmatic IMO.

The next question is - what does the compiler produce? My idea is that it produces pickles! More specifically a list of PickledCase (compiled scenarios). This is a struct that is completely decoupled from the Gherkin AST - it only has a source array with Location to produce a stack trace.

The pickles would eventually move to a separate repo/library, and Cucumber implementations will only depend on pickles for the runtime. This would enable is to come up with alternative formats for Cucumber, such as Markdown or even Excel. Just write another parser/compiler that produces pickles.

Let me know what you think. /cc @gasparnagy @muhqu @jbpros @tooky @mattwynne @everzet @stof

— Reply to this email directly or view it on GitHub.

aslakhellesoy commented 9 years ago

@sebrose thanks for the heads up about http://www.picklesdoc.com/

We should avoid name overloading. It doesn't matter too much what it's called - it's a lib used by implementors only - it will never be user-visible.

I think testicle would be great, but I'm worried some people might make a fuss about it. People have made a fuss about smaller things. It doesn't matter - gherkle, icicle, whatever.

I know you probably have great ideas for names, but let's not derail this discussion ;-)

sebrose commented 9 years ago

On 1 Apr 2015, at 13:44, Aslak Hellesøy notifications@github.com wrote:

@sebrose thanks for the heads up about http://www.picklesdoc.com/

We should avoid name overloading. It doesn't matter too much what it's called - it's a lib used by implementors only - it will never be user-visible.

Understood.

I think testicle would be great, but I'm worried some people might make a fuss about it. People have made a fuss about smaller things. It doesn't matter - gherkle, icicle, whatever.

I know you probably have great ideas for names, but let's not derail this discussion ;-)

Agreed

— Reply to this email directly or view it on GitHub.

stof commented 9 years ago

@aslakhellesoy I'm wondering how the formatting layer would deal with scenario outlines if cucumber only deals with PickledCase objects. Same for formatting feature backgrounds. Would it have to deal with both the gherkin AST and the run output to match them by location ?

And when would the filtering of features/scenarios based on tags would happen to decide whether they should be run ? Tags don't seem to appear at all in your PickledCase

aslakhellesoy commented 9 years ago

@stof regarding formatting I'm not sure! The funny thing with Background is that they run several times, so printing them once always seemed a little weird to me.

The pickles could have a back-reference to the AST nodes, making it easier to write a formatter that prints the original structure, but that also means we're maintaining the tight coupling to Gherkin I'd like to get away from. Can anyone suggest any smart algorithms/design patterns here?

Regarding tags - they will be compiled into the pickles too - I just haven't bothered with it yet since I'm still trying out different designs.

muhqu commented 9 years ago

I think the gherkin lib should only deal with parsing text to some structured form (e.g. AST). It should not assume on how this structured form will be used later (e.g. Visitable/runable). Also resolving background steps (or examples in scenario outlines) is something that should not be part of the parser. This is only important for runners (cucumber, behat, ...) but not for tools like formatters, suggestors (IDE integration).

For example for XML you have the choice to use a SAX-Parser (emitting events while parsing) or a DOM-Parser (building up a structured form of the text being parsed). Usually you implement the DOM-Parser using the SAX-Parser... Anything related to interpreting the data is not part of the parser.

I don't think that the 'pickles' belong to 'gherkin'. But maybe I'm missing something here... ;-)

gasparnagy commented 9 years ago

I think the logic, how to interpret the Gherkin language (e.g. background steps are injected before every scenario), scenario outline text placeholders are substituted, tags are "inherited") are belonging the the language semantics. So it is not that bad to keep them together, so that we have a standardized semantics across the tools. The repo is called gharkin3 and not gherkin3 parser, even though we concentrated on the parser so far.

Visitor: My vote is not to use visitors in the AST, but the different usages (compiler, formatting) should traverse the tree as they want.

stof commented 9 years ago

@gasparnagy the question is whether the compiler and the parser should live in the same package or be fully separate (with the compiler depending on the parser of course)

aslakhellesoy commented 9 years ago

I agree with @muhqu that the parser shouldn't do anything else than producing an AST. The parser has no dependencies on the compiler. The compiler depends on (consumes) the AST produced by the parser.

The question is whether we put the compiler in the same git repo/library as the parser. I agree with @gasparnagy - I think we should.

It could of course live in a separate git repo, but I think there are several benefits in keeping them in the same repo:

I think the pickles (the output of the compiler) should live in a separate library however. So this is what I have in mind:

                                       ┌─────────┐                        
                                       │Cucumber │                        
                                       └─────────┘                        
┌─────────────────────────┐                 │                             
│      Gherkin3 lib       │                 │                             
│                         │                 │                             
│ ┌─────────┐ ┌─────────┐ │                 ▼                  ┌─────────┐
│ │Gherkin3 │ │Gherkin3 │ │            ┌─────────┐             │  Excel  │
│ │ Parser  │ │Compiler │─┼───────────▶│ Pickles │◀────────────│Compiler │
│ └─────────┘ └─────────┘ │            └─────────┘             └─────────┘
└─────────────────────────┘                 ▲                             
                                            │                             
                                            │                             
                                            │                             
                                            │                             
                                            │                             
                                            │                             
                                       ┌─────────┐                        
                                       │Markdown │                        
                                       │Compiler │                        
                                       └─────────┘                        

Makes sense?

(I love Monodraw)

mattwynne commented 9 years ago

Makes sense to me @aslakhellesoy. I think Cucumber might also need a dependency on the various compilers, but that's a side issue.

On names, I'm comfortable sticking with the name cucumber-ruby-core as the home for Cucumber::Core::Test::Case, Cucumber::Core::Test::Step, Cucumber::Core::Test::Runner and the various Cucumber::Core::Test::Result types. Boring, maybe, but this is Cucumber's core domain, and for us in Ruby at least, that's where the code already lives. I did have a play with ideas for a more vivid / metaphorical name for this library once we hollow out the dependencies on Gherkin, and I didn't come up with anything as nice as Pickles, which I do like. It works for me if everyone else is on board, but I'm ambivalent.

aslakhellesoy commented 9 years ago

I've given this some more thought, and I think that while we're all working together to figure out what the structure of those pickles should be, the most pragmatic approach is to keep it all in the Gherkin3 repo/library:

                               ┌─────────┐                    
        ┌─────────────┬────────│Cucumber │──────────────┐     
        │             │        └─────────┘              │     
        │             │             │                   │     
        │             │             │                   │     
        │             │             │                   │     
        │             │             │                   │     
┌───────┼─────────────┼─────────────┼───────┐           │     
│       │             │             │       │           │     
│       ▼             ▼             ▼       │           ▼     
│  ┌─────────┐   ┌─────────┐   ┌─────────┐  │      ┌─────────┐
│  │Gherkin3 │   │Gherkin3 │   │ Pickles │  │      │Markdown │
│  │ Parser  │   │Compiler │──▶│         │◀─┼──────│Parser / │
│  └─────────┘   └─────────┘   └─────────┘  │      │Compiler │
└───────────────────────────────────────────┘      └─────────┘
                Gherkin3 lib                                  

Once it stabilises we can re-evaluate whether it makes sense to move pickles and perhaps the compiler too into separate projects.

mattwynne commented 9 years ago

Another approach is to refactor from the existing Ruby codebase, which already has a pickles in the form of cucumber-ruby-core. We’d just need to make it work with the new AST.

gasparnagy commented 9 years ago

I had a look at the current WIP version. I think it is fine. I have two comments:

  1. naming of the pickles - i understand the concept, that the pickle has a single name, so it contains the "Scenario: " prefix too (there is no keyword / name separation in pickle level), but this brings up interesting problems of how to name the SO examples. The current solution (take the first keyword for Scenario) might lead to interesting problems. I don't have a better solution though.
  2. reference the original AST elements - my idea is that the compiler should use a factory to create the pickle elements, and different sources, like Gherkin could implement the factory in a way that it creates subclass instances of the pickle elements (e.g. GherkinScenarioPickle) that can hold strong reference to the source AST node. If a formatter knows about Gherkin (or other potential pickle source) it can downcast the Pickle and use the AST for displaying richer result, otherwise (if the source format is unknown) it should just display what the Pickle directly contains.
mattwynne commented 9 years ago

On 7 Apr 2015, at 20:17, Gáspár Nagy notifications@github.com wrote: I had a look at the current WIP version. I think it is fine. I have two comments:

naming of the pickles - i understand the concept, that the pickle has a single name, so it contains the "Scenario: " prefix too (there is no keyword / name separation in pickle level), but this brings up interesting problems of how to name the SO examples. The current solution (take the first keyword for Scenario) might lead to interesting problems. I don't have a better solution though.

Have you looked at how we’ve named test cases in cucumber-ruby-core?

e.g. https://github.com/cucumber/cucumber-ruby-core/blob/master/spec/cucumber/core/test/case_spec.rb#L100 https://github.com/cucumber/cucumber-ruby-core/blob/master/spec/cucumber/core/test/case_spec.rb#L100

gasparnagy commented 9 years ago

@mattwynne yep, good point. we do something similar in SpecFlow. There we check if the first column has unique values and if yes, we use that instead of #1, #2, etc.

But my question was rather the beginning of the string, so whether it should be prefixed with the keyword ("Scenario: outline name, examples name (#1)" vs "outline name, examples name (#1)").

brasmusson commented 9 years ago

Or if there should be a keyword/name separation in the pickle level, as for test cases in cucumber-ruby-core.

In Cucumber v2.0 that separation enables that when hooks access the name of the running test case they get the name (outline name, example name (#row) for a test case from a Scenario Outline). But when listing failed test cases at the end of the run both the keyword and the name are used (Scenario Outline: outline name, example name (#row) for a test case from a Scenario Outline).

aslakhellesoy commented 9 years ago

Keep in mind that we want to generate pickles from other sources than Gherkin. Markdown is high on my list.

If we mandate the use of a keyword in pickles I think we're limiting our freedom to use other sources where a keyword isn't natural.

muhqu commented 9 years ago

@aslakhellesoy so Pickles is what the README is referring to as Test cases?

…if so, then why not just write a simple tool that transforms the AST-JSON to some TestCase-JSON?

Sry, if I'm missing the point here. :-/


In code what's on my mind...

some.feature:

Feature: Consuming Cucumbers

  Scenario: eat 5 out of 12
    Given there are 12 cucumbers
     When I eat 5 cucumbers
     Then I should have 7 cucumbers

some.feature-ast.json:

{
  "location": { "line": 1, "column": 1 },
  "type": "Feature",
  "tags": [ ],
  "language": "en",
  "keyword": "Feature",
  "name": "Consuming Cucumbers",
  "scenarioDefinitions": [
    {
      "location": { "line": 3, "column": 3 },
      "type": "Scenario",
      "keyword": "Scenario",
      "name": "eat 5 out of 12",
      "steps": [
        {
          "location": { "line": 4, "column": 5 },
          "type": "Step",
          "keyword": "Given ",
          "text": "there are 12 cucumbers"
        },
        {
          "location": { "line": 5, "column": 6 },
          "type": "Step",
          "keyword": "When ",
          "text": "I eat 5 cucumbers"
        },
        {
          "location": { "line": 6, "column": 6 },
          "type": "Step",
          "keyword": "Then ",
          "text": "I should have 7 cucumbers"
        }
      ],
      "tags": [ ]
    }
  ],
  "comments": [ ]
}

some.testcase.json:

{
 "cases": [
  {
   "name": "Consuming Cucumbers: eat 5 out of 12",
   "sources": [ { "file":"some.feature", "line": 3, "column": 3 } ],
   "steps": [
    {
     "sources": [ { "file":"some.feature", "line": 4, "column": 5 } ],
     "text": "there are 12 cucumbers"
    },
    {
     "sources": [ { "file":"some.feature", "line": 5, "column": 6 } ],
     "text": "I eat 5 cucumbers"
    },
    {
     "sources": [ { "file":"some.feature", "line": 6, "column": 6 } ],
     "text": "I should have 7 cucumbers"
    }
   ]
  }
 ]
}
aslakhellesoy commented 9 years ago

@muhqu:

so Pickles is what the README is referring to as Test cases?

Yes. I've updated the README.

why not just write a simple tool that transforms the AST-JSON to some TestCase-JSON

That's what Compiler.java does, except that it transforms AST objects to Pickle objects - it doesn't operate on the JSON level. Keep in mind this is work in progress / in flux. We'll have to integrate it into a Cucumber impl to see how well the abstraction works.

Sry, if I'm missing the point here. :-/

Read my updates to the README again and tell me if anything is still unclear.

mattwynne commented 9 years ago

Yeah I agree that Pickes should not know about Gherkin, very important.

The way our stuff currently works on Ruby core, you could take a Pickles Test::Case and ask it to describe its source to you. You’d get callbacks like step, scenario, background etc that tell you where the thing came from, so you could use those to get the keyword (or the bare name) if you needed it. Seems to me that a Pickle’s name should probably include the keyword, though it might be a bit a bit weird with an example row.

muhqu commented 9 years ago

@aslakhellesoy

Read my updates to the README again and tell me if anything is still unclear.

It's fine now. I think I understand now.

So, the Pickles object hierarchy represents a materialized view on the steps per test case (scenario). But each step object in these test cases keeps a reference to the original step node (/object) from the AST. The runner (cucumber) only needs to match its step definitions against the steps from the pickles hierarchy to run the test cases.

But where will the runner report the results to? e.g. which steps passed, failed, where skipped or ignored because there was no matching step def found...

Should the Pickles model (and the Gherkin model) also provide the capability to track the result of a step being run? …If the runner should not need to know about the Pickles source (being it Gherkin, markdown, u-name-it...) and how to render a source specific report, there needs to be some step result propagation between the Pickles model and the source model (Gherkin AST)...

I mean, ideally it should be capable of rendering the raw gherkin feature file with some highlighting which steps passed, failed or where skipped.

Of course this step state propagation is not 1:1. For example the steps from Background and Scenario Outlines will be evaluated more than once and therefor have a 1:N relation to the steps from the Pickles test case.

brasmusson commented 9 years ago

Currently there are two different approaches how to report results from the execution of feature files, one in Cucumber(-Ruby) and one in Cucumber-JVM. Cucumber(-Ruby) follow the feature file closely (background only reported once, normally reporting the result of test cases from Scenario Outlines on the example table row), whereas Cucumber-JVM follow the executed test cases more closely (background reported every time it is executed, report each step executed for test cases from Scenario Outlines).

When saying "ideally it should be capable of rendering the raw gherkin feature file with some highlighting" you are asking for what Cucumber(-Ruby) currently does @muhqu , but that is not the only approach as shown by the current behavior of Cucumber-JVM.

In case of reports intended for other tools to consume, like currently the json-report produced by the json-formatters (read by masterthoughts cucumber-reporting tools, bamboo-plugins and probably more), it is IMHO essential that there is an explicit result reported for each step executed (for instance one result for each time a background step was executed).

muhqu commented 9 years ago

@brasmusson I'm absolutely aware that there are various different report output formats.

What I wanted to highlight is that it should be _capable_ of rendering the raw gherkin feature with highlighting. I was just wondering how that could/would be achieved and to which software component this rendering would belong to. Maybe it's a good idea to keep the parsing and rendering of test cases results (in the test cases native source format) in the same place?

aslakhellesoy commented 9 years ago

I'd like to change the way reporting is done. I don't like the way it's done in either Cucumber-Ruby or Cucumber-JVM.

I think it was a mistake to include the source (AST) in the JSON report. It makes everything very complicated. The reporting API can be much simpler. All we need to report is the results, and a link to the input source (file, line and column). Something like this:

{
  "results": [
    {
      "uri": "file:///path/to/the.feature",
      "location": {"line": 22, "column": 4},
      "status": "failed",
      "error": "some stack trace",
      "startTimeMillis": 1428567433625,
      "durationMillis": 12
    }
  ]
}

Generating nice looking reports (HTML) can then be done by reading in the source again (which is easy with the new Gherkin3 API), and merge in the results.

The API could be something like this (Java):

public interface ResultsPlugin {
    void testRunStarted();
    void testStarted(TestCase testCase);
    void testStepStarted(TestStep testStep);
    void testStepFinished(TestStep testStep, TestStepResult result);
    void testFinished(TestCase testCase);
    void testRunFinished();
}

Note that we're not using Pickles here, but TestCases. A TestCase wraps a Pickle, and a TestStep wraps a PickleStep (and a Step Definition). A TestStep can also wrap just a before hook or after hook.

The difficult bit is the pretty formatter. I'm toying with the idea that when the pretty formatter receives a testStepStarted message we simply print everything in the file verbatim up until the line of the TestStep. When the step is finished we can move the cursor up one line (using ansi codes) and print the line again, red, green, amber or blue - depending on the status. For non-ANSI terminals we wouldn't print the step until it's finished.

This approach should work well when scenarios are run sequentially, in a single thread.

We're going to make Cucumber able to run scenarios in random order, possibly multi-threaded. In this case I think we should either disable the pretty formatter, or change its behaviour. It doesn't make sense to pretty-print scenarios (especially the feature headers) in random order.

muhqu commented 9 years ago

Generating nice looking reports (HTML) can then be done by reading in the source again (which is easy with the new Gherkin3 API), and merge in the results.

Reading the source again and having to match the results to Scenario's Steps by location (line/column) doesn't feel that natural, but probably would be a feasible solution.

Note that we're not using Pickles here, but TestCases. A TestCase wraps a Pickle, and a TestStep wraps a PickleStep (and a Step Definition).

Ok, but what does the Test(Case|Step) adds to the wrapped Pickle(Case|Step)? …the matched Step Def callback (if any)?

mattwynne commented 9 years ago

Bear in mind that as of Cucumber 2.0 much of what @aslakhellesoy describes is already live in Cucumber Ruby. For example, the new formatter API, which I admit is currently poorly documented, now works exactly like that.

I think this discussion might be informed by some reading of the cucumber-ruby-core source code, notably the runner. And the compiler which works off the Gherin2 AST at the moment.

@aslakhellesoy and I have some time in the same room next week so hopefully we can start trying to move this code over to work with Gherkin3 and see what problems come out of it.

aslakhellesoy commented 9 years ago

@muhqu - yes - it adds the stepdef. There is also a flavour for hooks. This is what I have in mind (Java):

interface TestStep {
    TestStepResult run();
}

public class PickleTestStep implements TestStep {
    public PickleTestStep(Pickle p, StepDefinifion sd) {}
}

public class HookTestStep implements TestStep {
    public HookTestStep(HookDefinifion hd) {}
}
muhqu commented 9 years ago

@mattwynne I hav to admit that I'm fairly new to 'cucumber' as a processor for gherkin. little bg: I worked like 4 years with behat and just recently switched to cucumber-jvm… with ruby I hav not much to do and like to keep it that way.. I have passion for go and gherkin, that's why I wrote the gherkin-go and go-gherkin parsers ;-)

@aslakhellesoy awesome, I think we're now on the same page… :clap:

aslakhellesoy commented 9 years ago

I'm glad it's becoming more clear. The various cucumber implementations are quite different on the inside, and I'm hopeful that we can document a high-level architecture that will make it easier for developers to make more consistent implementations!

The discussions we're having here are very useful. I'll do my best to document the important design decisions about Cucumber over at the cukes.info site. I think the new Gherkin architecture is already documented quite well in this project :-)

ghost commented 9 years ago

@muhqu I was wondering, wouldn't it be better to use an RDF vocab with e.g. JSON-LD by the AST format instead of using plain JSON? I wasn't checked the compiler yet, but JSON-LD transformations might come in handy and the AST would have more semantic either.

It could be something like this roughly, but I am not a JSON-LD expert:

gherkin

Feature: Example feature
  As a user of cucumber.js
  I want to have documentation on cucumber
  So that I can concentrate on building awesome applications

  Scenario: Reading documentation
    Given I am on the Cucumber.js GitHub repository
    When I go to the README file
    Then I should see "Usage" as the page title

AST RDF

{
    "@context": {
        "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
        "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
        "cucumber": "http://cucumber.org/vocab.jsonld#"
    },
    "@id": "http://example.com/features#",
    "features": [
        {
            "@type": "cucumber:Feature",
            "label": "Example feature",
            "description": [
                "As a user of cucumber.js",
                "I want to have documentation on cucumber",
                "So that I can concentrate on building awesome applications"
            ],
            "scenarios": [
                {
                    "@type": "cucumber:Scenario",
                    "label": "Reading documentation",
                    "steps": [
                        {
                            "@type": "cucumber:Given",
                            "label": "I am on the Cucumber.js GitHub repository"
                        },
                        {
                            "@type": "cucumber:When",
                            "label": "I go to the README file"
                        },
                        {
                            "@type": "cucumber:Then",
                            "label": "I should see "Usage" as the page title"
                        }
                    ]
                }
            ]
        }
    ]
}
aslakhellesoy commented 9 years ago

Currently, the only reason the AST (and compiled AST) have a JSON representation is for shared tests. The shared tests compare the JSON representation of the AST with an expected JSON document.

The JSON representation isn't currently used for anything else, but I can imagine it could be used for rendering/reporting - you could take a Gherkin AST as JSON and use it to generate a pretty HTML document for example.

@inf3rno can you give us a concrete example of what capabilities JSON-LD would give us that the current format doesn't give us? It appears the change would only require changing type to @type and adding a @context attribute. That doesn't seem too intrusive, but I'm still not clear on the benefits.

ghost commented 9 years ago

@aslakhellesoy

JSON can describe only hierarchical data structures, while JSON-LD can describe graphs. With this structure it does not matter, but by using tags you'll need to use graph, if you add properties to each tag, not just a label.

Another feature that it can annotate the properties with metadata, because it is an RDF format. E.g. the @type means http://www.w3.org/1999/02/22-rdf-syntax-ns#type here, the label means http://www.w3.org/1999/02/22-rdf-syntax-ns#label, the features means http://cucumber.org/vocab.jsonld#features, etc... Each URI identifies a specific term. By dereferencing the URIs, e.g. http://www.w3.org/1999/02/22-rdf-syntax-ns you will get vocabulary descriptions. So for example if you define a gherkin vocab, then you will be able to use it as context, and by parsing and traversing the JSON-LD you will be able to use the labels and descriptions you wrote into this gherkin vocab.

It is hard to tell whether you really need it. I think Markus could tell you more about the advantages and disadvantages of having an RDF vocab, he is an expert in the topic.

Probably having an RDF vocab would help to reuse feature descriptions amongst projects. So for example by testing common features like auth (login, logout), user catalog (edit profile, change password, reset password, etc...) or webshop (product catalog, cart, checkout, shipping), etc... It would be nice to import existing feature descriptions, select the ones needed for the project and implement only the step definitions. If you can add another standard vocab, which contains the features, then it would be possible to write automated clients, which can work by any application, which shares e2e tests publicly. Anyways, most of the testing code can be reused to write automated clients, for example by testing a REST API this can be very useful for 3rd party developers. But that's just a vision, probably it is beyond the boundaries of this project.

Zearin commented 9 years ago

For pretty-printing I think a breadth-first traversal is best.

Wouldn’t breadth-first also better suit parallel processing? It would be nice to plan for that possible future, especially for larger test suites (or frequent builds on CI servers)…

aslakhellesoy commented 8 years ago

The compiler isnow released (java, ruby, python, js) so I'm closing this