Skip to content
This repository has been archived by the owner on May 28, 2019. It is now read-only.

Compiler design and pickles #12

Closed
aslakhellesoy opened this issue Apr 1, 2015 · 34 comments
Closed

Compiler design and pickles #12

aslakhellesoy opened this issue Apr 1, 2015 · 34 comments

Comments

@aslakhellesoy
Copy link
Contributor

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
Copy link

sebrose commented Apr 1, 2015

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 [email protected] 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
Copy link
Contributor Author

@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
Copy link

sebrose commented Apr 1, 2015

On 1 Apr 2015, at 13:44, Aslak Hellesøy [email protected] 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
Copy link

stof commented Apr 1, 2015

@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
Copy link
Contributor Author

@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
Copy link
Contributor

muhqu commented Apr 1, 2015

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... ;-)

  • Mathias

@gasparnagy
Copy link
Contributor

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
Copy link

stof commented Apr 1, 2015

@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
Copy link
Contributor Author

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:

  • Leverage the same shared test suite we have now
  • Easier to refactor
  • Easier to manage releases
  • Easier to keep things in sync (this is important)

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
Copy link
Contributor

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
Copy link
Contributor Author

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

On 7 Apr 2015, at 20:17, Gáspár Nagy [email protected] 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
Copy link
Contributor

@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
Copy link
Contributor

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
Copy link
Contributor Author

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
Copy link
Contributor

muhqu commented Apr 8, 2015

@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
Copy link
Contributor Author

@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
Copy link
Contributor

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
Copy link
Contributor

muhqu commented Apr 8, 2015

@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
Copy link
Contributor

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
Copy link
Contributor

muhqu commented Apr 9, 2015

@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
Copy link
Contributor Author

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
Copy link
Contributor

muhqu commented Apr 9, 2015

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
Copy link
Contributor

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
Copy link
Contributor Author

@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
Copy link
Contributor

muhqu commented Apr 9, 2015

@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… 👏

@aslakhellesoy
Copy link
Contributor Author

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
Copy link

ghost commented May 24, 2015

@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
Copy link
Contributor Author

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
Copy link

ghost commented May 24, 2015

@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
Copy link
Contributor

Zearin commented Sep 3, 2015

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
Copy link
Contributor Author

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants