Code Monkey home page Code Monkey logo

cucumber / gherkin Goto Github PK

View Code? Open in Web Editor NEW
162.0 109.0 48.0 10.28 MB

A parser and compiler for the Gherkin language.

License: MIT License

Makefile 1.26% CMake 1.37% jq 0.15% HTML 2.61% C 14.91% Dart 7.83% C# 9.29% Shell 0.25% Elixir 6.63% Go 5.34% Gherkin 0.06% Ruby 5.28% Groovy 0.07% Java 7.64% TypeScript 5.65% Objective-C 9.47% Perl 7.82% PHP 8.09% Python 6.27% JavaScript 0.03%
gherkin polyglot-release c dart dotnet elixir go java javascript lexer

gherkin's Introduction

Gherkin

Gherkin is a parser and compiler for the Gherkin language.

Gherkin is currently implemented for the following platforms (in order of birthday):

The CI will run using the linked workflow when that specific language implementation is changed

The CI will also run for any/all linked workflows when any test data is modified (For example modifying one of the good or bad features / ndjson outputs)

Contributing Translations (i18n)

In order to allow Gherkin to be written in a number of languages, the keywords have been translated into multiple languages. To improve readability and flow, some languages may have more than one translation for any given keyword.

If you are looking to add, update or improve these translations please see CONTRIBUTING.md.

Contributing a Parser Implementation

See CONTRIBUTING.md if you want to contribute a parser for a new programming language. Our wish-list is (in no particular order):

  • Rust

Usage

Gherkin can be used either through its command line interface (CLI) or as a library.

It is designed to be used in conjunction with other tools such as Cucumber which consumes the output from the CLI or library as Cucumber Messages.

Library

Using the library is the preferred way to use Gherkin since it produces easily consumable AST and Pickle objects in-process without having to fork a CLI process or parse JSON.

The library itself provides a stream API, which is what the CLI is based on. This is the recommended way to use the library as it provides a high level API that is easy to use. See the CLI implementations to get an idea of how to use it.

Alternatively, you can use the lower level parser and compiler. Some usage examples are below:

Java

Path path = Paths.get("../testdata/good/minimal.feature");
GherkinParser parser = GherkinParser.builder().build();
Stream<Envelope> pickles = parser.parse(envelope).filter(envelope -> envelope.getPickle().isPresent());

C#

var parser = new Parser();
var gherkinDocument = parser.Parse(@"Drive:\PathToGherkinDocument\document.feature");

Ruby

require 'gherkin/parser'
require 'gherkin/pickles/compiler'

source = {
  uri: 'uri_of_the_feature.feature',
  data: 'Feature: ...',
  mediaType: 'text/x.cucumber.gherkin+plain'
}

gherkin_document = Gherkin::Parser.new.parse(source[:data])
id_generator = Cucumber::Messages::IdGenerator::UUID.new

pickles = Gherkin::Pickles::Compiler.new(id_generator).compile(gherkin_document, source)

JavaScript

var Gherkin = require("@cucumber/gherkin");
var Messages = require("@cucumber/messages");

var uuidFn = Messages.IdGenerator.uuid();
var builder = new Gherkin.AstBuilder(uuidFn);
var matcher = new Gherkin.GherkinClassicTokenMatcher(); // or Gherkin.GherkinInMarkdownTokenMatcher()

var parser = new Gherkin.Parser(builder, matcher);
var gherkinDocument = parser.parse("Feature: ...");
var pickles = Gherkin.compile(
  gherkinDocument,
  "uri_of_the_feature.feature",
  uuidFn
);

Go

// Download the package via: `go get github.com/cucumber/gherkin/go/v27`
//   && go get "github.com/cucumber/messages/go/v22"
import (
  "strings"

  gherkin "github.com/cucumber/gherkin/go/v27"
  messages "github.com/cucumber/messages/go/v22"
)

func main() {
  uuid := &message.UUID{} // or &message.Incrementing{}
  reader := strings.NewReader(`Feature: ...`)
  gherkinDocument, err := gherkin.ParseGherkinDocument(reader, uuid.NewId)
  pickles := gherkin.Pickles(*gherkinDocument, "minimal.feature", uuid.NewId)
}

Python

from gherkin.parser import Parser
from gherkin.pickles.compiler import Compiler

parser = Parser()
gherkin_document = parser.parse("Feature: ...")
gherkin_document["uri"] = "uri_of_the_feature.feature"
pickles = Compiler().compile(gherkin_document)

Objective-C

#import "GHParser+Extensions.h"

GHParser * parser = [[GHParser alloc] init];
NSString * featureFilePath; // Should refer to the place where we can get the content of the feature
NSString * content = [NSString stringWithContentsOfURL:featureFilePath encoding:NSUTF8StringEncoding error:nil];
if([content stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0){
      // GHParser will throw an error if you passed empty content... handle this issue first.
}
GHGherkinDocument * result = [parser parseContent:content];

Perl

use Gherkin::Parser;
use Gherkin::Pickles::Compiler;

my $parser = Gherkin::Parser->new();
my $gherkin_document = $parser->parse("Feature: ...");
my $pickles = Gherkin::Pickles::Compiler->compile($gherkin_document);

PHP

use Cucumber\Gherkin\GherkinParser;

$path = '/path/to/my.feature';

$parser = new GherkinParser();
$pickles = $parser->parseString(uri: $path, data: file_get_contents($path));

CLI

The Gherkin CLI gherkin reads Gherkin source files (.feature files) and outputs ASTs and Pickles.

The gherkin program takes any number of files as arguments and prints the results to STDOUT as Newline Delimited JSON.

Each line is a JSON document that conforms to the Cucumber Event Protocol.

To try it out, just install Gherkin for your favourite language, and run it over the files in this repository:

gherkin testdata/**/*.feature

Ndjson is easy to read for programs, but hard for people. To pretty print each JSON document you can pipe it to the jq program:

gherkin testdata/**/*.feature | jq

Table cell escaping

If you want to use a newline character in a table cell, you can write this as \n. If you need a | as part of the cell, you can escape it as \|. And finally, if you need a \, you can escape that with \\.

Architecture

The following diagram outlines the architecture:

graph LR
    A[Feature file] -->|Scanner| B[Tokens]
    B -->|Parser| D[AST]
Loading

The scanner reads a gherkin doc (typically read from a .feature file) and creates a token for each line. The tokens are passed to the parser, which outputs an AST (Abstract Syntax Tree).

If the scanner sees a #language header, it will reconfigure itself dynamically to look for Gherkin keywords for the associated language. The keywords are defined in gherkin-languages.json.

The scanner is hand-written, but the parser is generated by the Berp parser generator as part of the build process.

Berp takes a grammar file (gherkin.berp) and a template file (gherkin-X.razor) as input and outputs a parser in language X:

graph TD
    A[gherkin.berp] --> B[berp.exe]
    C[gherkin-X.razor] --> B
    B --> D[Parser.x]
Loading

Abstract Syntax Tree (AST)

The AST produced by the parser can be described with the following class diagram:

classDiagram
    ScenarioOutline --|> ScenarioDefinition
    GherkinDocument "1" *-- "0..1" Comment: comment
    GherkinDocument "1" *-- "0..1" Feature: feature
    Feature "1" *-- "0..*" ScenarioDefinition: scenarioDefinitions
    Feature "1" *-- "0..*" Rule: rules
    Rule "1" *-- "0..*" ScenarioDefinition: scenarioDefinitions
    Background "0..1" --* "1" Rule: background
    Feature "1" *-- "0..1" Background: background
    Scenario --|> ScenarioDefinition
    Tag "0..*" --* "1" Feature: tags
    Tag "0..*" --* "1" Scenario: tags
    Tag "0..*" --* "1" ScenarioOutline: tags
    Tag "0..*" --* "1" Examples: tags
    Examples "0..*" --* "1" ScenarioOutline: examples
    TableRow "1" --* "1" Examples: header
    TableRow "0..*" --* "1" Examples: rows
    Background "1" *-- "0..*" Step: steps
    Step "0..*" --* "1" ScenarioDefinition: steps
    StepArgument "0..1" --* "1" Step: stepArgument
    DataTable --|> StepArgument
    StepArgument <|-- DocString
    TableRow "0..*" --* "1" DataTable: rows
    TableRow "1" *-- "0..*" TableCell: cells
    class ScenarioDefinition {
        keyword
        name
        description
    }
    class Step {
        keyword
        text
    }
    class Examples {
        keyword
        name
        description
    }
    class Feature {
        language
        keyword
        name
        description
    }
    class Background {
        keyword
        name
        description
    }
    class Rule {
        keyword
        name
        description
    }
    class DocString {
        content
        contentType
    }
    class Comment {
        text
    }
    class TableCell {
        value
    }
    class Tag {
        name
    }
    class Location {
        line: int
        column: int
    }
Loading

Every class represents a node in the AST. Every node has a Location that describes the line number and column number in the input file. These numbers are 1-indexed.

All fields on nodes are strings (except for Location.line and Location.column).

The implementation is simple objects without behaviour, only data. It's up to the implementation to decide whether to use classes or just basic collections, but the AST must have a JSON representation (this is used for testing).

Each node in the JSON representation also has a type property with the name of the node type.

You can see some examples in the testdata/good directory.

Pickles

The AST isn't suitable for execution by Cucumber. It needs further processing into a simpler form called Pickles.

The compiler compiles the AST produced by the parser into pickles:

graph LR
    A[AST] -->|Compiler| B[Pickles]
Loading

The rationale is to decouple Gherkin from Cucumber so that Cucumber is open to support alternative formats to Gherkin (for example Markdown).

The simpler Pickles data structure also simplifies the internals of Cucumber. With the compilation logic maintained in the Gherkin library we can easily use the same test suite for all implementations to verify that compilation is behaving consistently between implementations.

Each Scenario will be compiled into a Pickle. A Pickle has a list of PickleStep, derived from the steps in a Scenario.

Each Examples row under Scenario Outline will also be compiled into a Pickle.

Any Background steps will also be compiled into a Pickle.

Every tag, like @a, will be compiled into a Pickle as well (inheriting tags from parent elements in the Gherkin AST).

Example:

@a
Feature:
  @b @c
  Scenario Outline:
    Given <x>

    Examples:
      | x |
      | y |

  @d @e
  Scenario Outline:
    Given <m>

    @f
    Examples:
      | m |
      | n |

Using the CLI we can compile this into several pickle objects:

gherkin testdata/good/readme_example.feature --no-source --no-ast | jq

Output:

{
  "type": "pickle",
  "uri": "testdata/good/readme_example.feature",
  "pickle": {
    "name": "",
    "steps": [
      {
        "text": "y",
        "arguments": [],
        "locations": [
          {
            "line": 9,
            "column": 7
          },
          {
            "line": 5,
            "column": 11
          }
        ]
      }
    ],
    "tags": [
      {
        "name": "@a",
        "location": {
          "line": 1,
          "column": 1
        }
      },
      {
        "name": "@b",
        "location": {
          "line": 3,
          "column": 3
        }
      },
      {
        "name": "@c",
        "location": {
          "line": 3,
          "column": 6
        }
      }
    ],
    "locations": [
      {
        "line": 9,
        "column": 7
      },
      {
        "line": 4,
        "column": 3
      }
    ]
  }
}
{
  "type": "pickle",
  "uri": "testdata/good/readme_example.feature",
  "pickle": {
    "name": "",
    "steps": [
      {
        "text": "n",
        "arguments": [],
        "locations": [
          {
            "line": 18,
            "column": 7
          },
          {
            "line": 13,
            "column": 11
          }
        ]
      }
    ],
    "tags": [
      {
        "name": "@a",
        "location": {
          "line": 1,
          "column": 1
        }
      },
      {
        "name": "@d",
        "location": {
          "line": 11,
          "column": 3
        }
      },
      {
        "name": "@e",
        "location": {
          "line": 11,
          "column": 6
        }
      },
      {
        "name": "@f",
        "location": {
          "line": 15,
          "column": 5
        }
      }
    ],
    "locations": [
      {
        "line": 18,
        "column": 7
      },
      {
        "line": 12,
        "column": 3
      }
    ]
  }
}

Each Pickle event also contains the path to the original source. This is useful for generating reports and stack traces when a Scenario fails.

Cucumber will further transform this list of Pickle objects to a list of TestCase objects. TestCase objects link to user code such as Hooks and Step Definitions.

Building Gherkin

See CONTRIBUTING.md

Markdown with Gherkin

See Markdown with Gherkin.

Projects using Gherkin

gherkin's People

Contributors

aslakhellesoy avatar aurelien-reeves avatar badeball avatar brasmusson avatar charlierudolph avatar chybz avatar ciaranmcnulty avatar cukebot avatar davidjgoss avatar dewjunkie avatar dmboyd avatar ehuelsmann avatar gasparnagy avatar johnknoop avatar kieran-ryan avatar l3pp4rd avatar luke-hill avatar mattwynne avatar mgiustiniani avatar milhcbt avatar mpkorstanje avatar mxygem avatar olleolleolle avatar renovate-bot avatar renovate[bot] avatar sabotageandi avatar sergioforerogomez avatar vincent-psarga avatar wannesfransen1994 avatar willmac321 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gherkin's Issues

Generate a feature file from a parsed document (de-parse effectively)

🤔 What's the problem you're trying to solve?

As one has the Parser like here:

parser = Parser()
gherkin_document = parser.parse("Feature: ...")

and has changed/updated a few elements of the gherkin_document (which is really just a dictionary in Python)
Isn't it logical for many instances to want to re-generate the feature file ?

✨ What's your proposed solution?

A script which extracts the information from within the Parsed Gherkin document and generates a valid .feature file with this feature

⛏ Have you considered any alternatives or workarounds?

If there is not none already the only way to go is to build one myself but for this community it would be a more mature solution if you could integrate it in this repo

📚 Any additional context?


This text was originally generated from a template, then edited by hand. You can modify the template here.

dart: Acceptance tests are not implemented

🤔 What's the problem you've observed?

The Gherkin Parser for Dart does not implement the acceptance tests (e.g. compare the make file to to the javascript implementation). This is a problem because:

As of May 2016 Gherkin is implemented in 8 languages. This number is likely to increase to a dozen within a year or two. Very few programmers are intimate with all those languages. Therefore, in order to make it as easy as possible to refactor, fix bugs, add features and release packages it is essential that all implementations have a similar structure.

CONTRIBUTING.md - consistency between implementations

✨ Do you have a proposal for making it better?

Either:

  • Use Berp to generate the parser.
  • Remove Dart.

📚 Any additional context?

The Parser for Dart is also not generated using Berp #29

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Repository problems

These problems occurred while renovating this repository. View logs.

  • WARN: Unsupported range strategy

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

bundler
ruby/Gemfile
composer
php/composer.json
  • php ^8.1
  • cucumber/messages >=19.1.4 <=24
  • phpunit/phpunit ^10.5||^11.0
  • vimeo/psalm 5.25.0
  • friendsofphp/php-cs-fixer ^3.51
  • psalm/plugin-phpunit ^0.19.0
cpanfile
perl/cpanfile
  • Getopt::Long 2.58
  • List::Util 1.63
github-actions
.github/workflows/release-cpan.yaml
  • actions/checkout v4
  • cucumber/action-publish-cpan v1.0.1
.github/workflows/release-github.yaml
  • actions/checkout v4
  • cucumber/action-create-github-release v1.1.1
.github/workflows/release-mvn.yml
  • actions/checkout v4
  • actions/setup-java v4
  • cucumber/action-publish-mvn v2.0.0
.github/workflows/release-npm.yml
  • actions/checkout v4
  • actions/setup-node v4
  • cucumber/action-publish-npm v1.1.1
.github/workflows/release-nuget.yaml
  • actions/checkout v4
  • actions/setup-dotnet v4
  • cucumber/action-publish-nuget v1.0.0
.github/workflows/release-php.yaml
  • actions/checkout v4
  • cucumber/action-publish-subrepo v1.1.1
.github/workflows/release-pypi.yaml
  • actions/checkout v4
  • actions/setup-python v5
  • cucumber/action-publish-pypi v2.0.0
.github/workflows/release-rubygem.yml
  • actions/checkout v4
  • ruby/setup-ruby v1
  • cucumber/action-publish-rubygem v1.0.0
.github/workflows/test-c.yml
  • actions/checkout v4
.github/workflows/test-codegen.yml
  • actions/checkout v4
  • actions/setup-dotnet v4
.github/workflows/test-cpp.yml
  • actions/checkout v4
  • ilammy/msvc-dev-cmd v1
.github/workflows/test-dart.yml
  • actions/checkout v4
  • dart-lang/setup-dart v1.4
.github/workflows/test-dotnet.yml
  • actions/checkout v4
  • actions/setup-dotnet v4
.github/workflows/test-go.yml
  • actions/checkout v4
  • actions/setup-go v5
.github/workflows/test-java.yml
  • actions/checkout v4
  • actions/setup-java v4
.github/workflows/test-javascript.yml
  • actions/checkout v4
  • actions/setup-node v4
.github/workflows/test-perl.yml
  • actions/checkout v4
  • shogo82148/actions-setup-perl v1
.github/workflows/test-php.yml
  • actions/checkout v4
  • shivammathur/setup-php v2
  • actions/cache v4
.github/workflows/test-python.yml
  • actions/checkout v4
  • actions/setup-python v5
.github/workflows/test-ruby.yml
  • actions/checkout v4
  • ruby/setup-ruby v1
gomod
go/go.mod
  • github.com/cucumber/messages/go/v24 v24.1.0
  • github.com/stretchr/testify v1.9.0
  • go 1.19
maven
java/pom.xml
  • io.cucumber:cucumber-parent 4.2.0
  • com.fasterxml.jackson:jackson-bom 2.17.1
  • org.junit:junit-bom 5.10.3
  • io.cucumber:messages [19.1.4,25.0.0)
  • org.codehaus.gmaven:groovy-maven-plugin 2.1.1
mix
elixir/mix.exs
  • elixir_uuid ~> 1.2
  • cucumber_messages ~> 15.0
  • ex_doc ~> 0.34
npm
javascript/package.json
  • @cucumber/messages >=19.1.4 <=24
  • @types/mocha 10.0.7
  • @types/node 20.14.9
  • commander ^12.0.0
  • core-js 3.37.1
  • mocha 10.5.2
  • ts-node 10.9.2
  • typescript 5.5.2
nuget
dotnet/Gherkin.Specs/Gherkin.Specs.csproj
  • dotnet-xunit 2.3.1
  • xunit.runner.visualstudio 2.8.1
  • xunit 2.8.1
  • Utf8Json 1.3.7
  • Microsoft.NET.Test.Sdk 17.10.0
  • FluentAssertions 6.12.0
pip_requirements
python/requirements.txt
  • pytest <8.3
  • pytest >= 5.0
pub
dart/pubspec.yaml
  • characters ^1.1.0
  • uuid ^4.0.0
  • path ^1.8.0
  • pedantic ^1.11.0
  • test ^1.17.4
  • dart ^3.1.0
regex
ruby/cucumber-gherkin.gemspec
  • cucumber-messages '>= 19.1.4', '< 24'
  • rake '~> 13.0', '>= 13.0.6'
  • rspec '~> 3.11', '>= 3.11.0'

  • Check this box to trigger a request for Renovate to run again on this repository

Missing colons are not reported as invalid syntax

Describe the bug
If the colon after a scenario is missing, the scenario is simply not run, instead of being reported as invalid
To Reproduce
Steps to reproduce the behavior:

  1. Create the following feature:
Feature: I am buggy

  Scenario: I put the colon in the end:
    Then I run the test
  1. Run the feature

Expected behavior
The scenario is reported as invalid
Context & Motivation

It costs a lot of time if this happens, because the misplaced colon is not obvious

Screenshots

Your Environment
Cucumber 6.8.1

Asciidoc Support

🤔 What's the problem you're trying to solve?

Feature: Add asciidoc support for feature formatting
Asciidoc is a feature rich alternative to markdown that covers almost everything that markdown does but
also adds much more

As a product owner
I want to use asciidoc formatting for my user stories
In order to better express my needs with well-formatted and pretty documents

As a quality engineer
I want to write examples (scenarios) using asciidoc
So that I can better express the features and underline important information using formatting and images

As a developer
I want to receive well-structured user stories to develop
So that I know exactly what I need to develop

As an end user
I want a pretty and well-formatted living documentation
So that I can quickly understand how the software works

As a tech lead
I want to generate a website using a tool like antora
In order to organize my documentation in a single well-structured documentation site

✨ What's your proposed solution?

There is currently a working markdown format so I think we can base ourselves on this module.
I haven't yet looked at the code though ..

⛏ Have you considered any alternatives or workarounds?

There is a project called cukedocktor that I have tried using for a while.
Unfortunately this project uses the old version of the cucumber framework pre-ndmessages and lacks some of the newer features
of the language like the rules.

It also seems like a redundant solution to the existing react html formatter.

📚 Any additional context?

Thanks for all of the hard work !


This text was originally generated from a template, then edited by hand. You can modify the template here.

perl: Adding a new translation has a dependency on perl

🤔 What's the problem you've observed?

When a contributor updates gherkin-languages.json they'll run make copy-gherkin-languages to copy this file and/or generate derived for each implementation. This process should be light weight only depend on a few tools such as jq, however for Perl, this process currently depends on Perl.

gherkin/perl/Makefile

Lines 32 to 37 in 1cc2ef0

copy-gherkin-languages: # lib/Gherkin/Generated/Languages.pm ## Copy gherkin-languages.json and/or generate derived files
echo "TODO: Depends on perl, this task should only depend on jq"
clean-gherkin-languages: ## Remove gherkin-languages.json and any derived files
# rm -f lib/Gherkin/Generated/Languages.pm
echo "TODO: Depends on perl, this task should only depend on jq"

✨ Do you have a proposal for making it better?

Consider using jq instead of perl to generate Languages.pm instead. For example see:

https://github.com/cucumber/gherkin/blob/1cc2ef0153603c5e51818b59ff6d632238491226/go/dialects_builtin.go.jq

perl: Languages.pm is not mergable

🤔 What's the problem you've observed?

Currently the generated Languages.pm consists of a single line.

package Gherkin::Generated::Languages;
use strict;
use warnings;
use utf8;
our $data = {'af',{'and',['* ','En '],'background',['Agtergrond'],'but',['* ','Maar '],'examples',['Voorbeelde'],'feature',['Funksie','Besigheid Behoefte','Vermoë'],'given',['* ','Gegewe '],'name','Afrikaans','native','Afrikaans','rule',['Regel'],'scenario',['Voorbeeld','Situasie'],'scenarioOutline',['Situasie Uiteensetting'],'then',['* ','Dan '],'when',['* ','Wanneer ']},'am',{'and',['* ','Եվ '],'background',['Կոնտեքստ'],'but',['* ','Բայց '],'examples',['Օրինակներ'],'feature',['Ֆունկցիոնալություն','Հատկություն'],'given',['* ','Դիցուք '],'name','Armenian','native','հայերեն','rule',['Rule'],'scenario',['Օրինակ','Սցենար'],'scenarioOutline',['Սցենարի կառուցվացքը'],'then',['* ','Ապա '],'when',['* ','Եթե ','Երբ ']},'amh',{'and',['* ','እና '],'background',['ቅድመ ሁኔታ','መነሻ','መነሻ ሀሳብ'],'but',['* ','ግን '],'examples',['ምሳሌዎች','ሁናቴዎች'],'feature',['ስራ','የተፈለገው ስራ','የሚፈለገው ድርጊት'],'given',['* ','የተሰጠ '],'name','Amharic','native','አማርኛ','rule',['ህግ'],'scenario',['ምሳሌ','ሁናቴ'],'scenarioOutline',['ሁናቴ ዝርዝር','ሁናቴ አብነት'],'then',['* ','ከዚያ '],'when',['* ','መቼ ']},'an',{'and',['* ','Y ','E '],'background',['Antecedents'],'but',['* ','Pero '],'examples',['Eixemplos'],'feature',['Caracteristica'],'given',['* ','Dau ','Dada ','Daus ','Dadas '],'name','Aragonese','native','Aragonés','rule',['Rule'],'scenario',['Eixemplo','Caso'],'scenarioOutline',['Esquema del caso'],'then',['* ','Alavez ','Allora ','Antonces '],'when',['* ','Cuan ']},'ar',{'and',['* ','و '],'background',['الخلفية'],'but',['* ','لكن '],'examples',['امثلة'],'feature',['خاصية'],'given',['* ','بفرض '],'name','Arabic','native','العربية','rule',['Rule'],'scenario',['مثال','سيناريو'],'scenarioOutline',['سيناريو مخطط'],'then',['* ','اذاً ','ثم '],'when',['* ','متى ','عندما ']},'ast',{'and',['* ','Y ','Ya '],'background',['Antecedentes'],'but',['* ','Peru '],'examples',['Exemplos'],'feature',['Carauterística'],'given',['* ','Dáu ','Dada ','Daos ','Daes '],'name','Asturian','native','asturianu','rule',['Rule'],'scenario',['Exemplo','Casu'],'scenarioOutline',['Esbozu del casu'],'then',['* ','Entós '],'when',['* ','Cuando ']},'az',{'and',['* ','Və ','Həm '],'background',['Keçmiş','Kontekst'],'but',['* ','Amma ','Ancaq '],'examples',['Nümunələr'],'feature',['Özəllik'],'given',['* ','Tutaq ki ','Verilir '],'name','Azerbaijani','native','Azərbaycanca','rule',['Rule'],'scenario',['Nümunə','Ssenari'],'scenarioOutline',['Ssenarinin strukturu'],'then',['* ','O halda '],'when',['* ','Əgər ','Nə vaxt ki ']},'bg',{'and',['* ','И '],'background',['Предистория'],'but',['* ','Но '],'examples',['Примери'],'feature',['Функционалност'],'given',['* ','Дадено '],'name','Bulgarian','native','български','rule',['Правило'],'scenario',['Пример','Сценарий'],'scenarioOutline',['Рамка на сценарий'],'then',['* ','То '],'when',['* ','Когато ']},'bm',{'and',['* ','Dan '],'background',['Latar Belakang'],'but',['* ','Tetapi ','Tapi '],'examples',['Contoh'],'feature',['Fungsi'],'given',['* ','Diberi ','Bagi '],'name','Malay','native','Bahasa Melayu','rule',['Rule'],'scenario',['Senario','Situasi','Keadaan'],'scenarioOutline',['Kerangka Senario','Kerangka Situasi','Kerangka Keadaan','Garis Panduan Senario'],'then',['* ','Maka ','Kemudian '],'when',['* ','Apabila ']},'bs',{'and',['* ','I ','A '],'background',['Pozadina'],'but',['* ','Ali '],'examples',['Primjeri'],'feature',['Karakteristika'],'given',['* ','Dato '],'name','Bosnian','native','Bosanski','rule',['Rule'],'scenario',['Primjer','Scenariju','Scenario'],'scenarioOutline',['Scenariju-obris','Scenario-outline'],'then',['* ','Zatim '],'when',['* ','Kada ']},'ca',{'and',['* ','I '],'background',['Rerefons','Antecedents'],'but',['* ','Però '],'examples',['Exemples'],'feature',['Característica','Funcionalitat'],'given',['* ','Donat ','Donada ','Atès ','Atesa '],'name','Catalan','native','català','rule',['Rule'],'scenario',['Exemple','Escenari'],'scenarioOutline',['Esquema de l\'escenari'],'then',['* ','Aleshores ','Cal '],'when',['* ','Quan ']},'cs',{'and',['* ','A také ','A '],'background',['Pozadí','Kontext'],'but',['* ','Ale '],'examples',['Příklady'],'feature',['Požadavek'],'given',['* ','Pokud ','Za předpokladu '],'name','Czech','native','Česky','rule',['Pravidlo'],'scenario',['Příklad','Scénář'],'scenarioOutline',['Náčrt Scénáře','Osnova scénáře'],'then',['* ','Pak '],'when',['* ','Když ']},'cy-GB',{'and',['* ','A '],'background',['Cefndir'],'but',['* ','Ond '],'examples',['Enghreifftiau'],'feature',['Arwedd'],'given',['* ','Anrhegedig a '],'name','Welsh','native','Cymraeg','rule',['Rule'],'scenario',['Enghraifft','Scenario'],'scenarioOutline',['Scenario Amlinellol'],'then',['* ','Yna '],'when',['* ','Pryd ']},'da',{'and',['* ','Og '],'background',['Baggrund'],'but',['* ','Men '],'examples',['Eksempler'],'feature',['Egenskab'],'given',['* ','Givet '],'name','Danish','native','dansk','rule',['Rule'],'scenario',['Eksempel','Scenarie'],'scenarioOutline',['Abstrakt Scenario'],'then',['* ','Så '],'when',['* ','Når ']},'de',{'and',['* ','Und '],'background',['Grundlage','Hintergrund','Voraussetzungen','Vorbedingungen'],'but',['* ','Aber '],'examples',['Beispiele'],'feature',['Funktionalität','Funktion'],'given',['* ','Angenommen ','Gegeben sei ','Gegeben seien '],'name','German','native','Deutsch','rule',['Rule','Regel'],'scenario',['Beispiel','Szenario'],'scenarioOutline',['Szenariogrundriss','Szenarien'],'then',['* ','Dann '],'when',['* ','Wenn ']},'el',{'and',['* ','Και '],'background',['Υπόβαθρο'],'but',['* ','Αλλά '],'examples',['Παραδείγματα','Σενάρια'],'feature',['Δυνατότητα','Λειτουργία'],'given',['* ','Δεδομένου '],'name','Greek','native','Ελληνικά','rule',['Rule'],'scenario',['Παράδειγμα','Σενάριο'],'scenarioOutline',['Περιγραφή Σεναρίου','Περίγραμμα Σεναρίου'],'then',['* ','Τότε '],'when',['* ','Όταν ']},'em',{'and',['* ','😂'],'background',['💤'],'but',['* ','😔'],'examples',['📓'],'feature',['📚'],'given',['* ','😐'],'name','Emoji','native','😀','rule',['Rule'],'scenario',['🥒','📕'],'scenarioOutline',['📖'],'then',['* ','🙏'],'when',['* ','🎬']},'en',{'and',['* ','And '],'background',['Background'],'but',['* ','But '],'examples',['Examples','Scenarios'],'feature',['Feature','Business Need','Ability'],'given',['* ','Given '],'name','English','native','English','rule',['Rule'],'scenario',['Example','Scenario'],'scenarioOutline',['Scenario Outline','Scenario Template'],'then',['* ','Then '],'when',['* ','When ']},'en-Scouse',{'and',['* ','An '],'background',['Dis is what went down'],'but',['* ','Buh '],'examples',['Examples'],'feature',['Feature'],'given',['* ','Givun ','Youse know when youse got '],'name','Scouse','native','Scouse','rule',['Rule'],'scenario',['The thing of it is'],'scenarioOutline',['Wharrimean is'],'then',['* ','Dun ','Den youse gotta '],'when',['* ','Wun ','Youse know like when ']},'en-au',{'and',['* ','Too right '],'background',['First off'],'but',['* ','Yeah nah '],'examples',['You\'ll wanna'],'feature',['Pretty much'],'given',['* ','Y\'know '],'name','Australian','native','Australian','rule',['Rule'],'scenario',['Awww, look mate'],'scenarioOutline',['Reckon it\'s like'],'then',['* ','But at the end of the day I reckon '],'when',['* ','It\'s just unbelievable ']},'en-lol',{'and',['* ','AN '],'background',['B4'],'but',['* ','BUT '],'examples',['EXAMPLZ'],'feature',['OH HAI'],'given',['* ','I CAN HAZ '],'name','LOLCAT','native','LOLCAT','rule',['Rule'],'scenario',['MISHUN'],'scenarioOutline',['MISHUN SRSLY'],'then',['* ','DEN '],'when',['* ','WEN ']},'en-old',{'and',['* ','Ond ','7 '],'background',['Aer','Ær'],'but',['* ','Ac '],'examples',['Se the','Se þe','Se ðe'],'feature',['Hwaet','Hwæt'],'given',['* ','Thurh ','Þurh ','Ðurh '],'name','Old English','native','Englisc','rule',['Rule'],'scenario',['Swa'],'scenarioOutline',['Swa hwaer swa','Swa hwær swa'],'then',['* ','Tha ','Þa ','Ða ','Tha the ','Þa þe ','Ða ðe '],'when',['* ','Bæþsealf ','Bæþsealfa ','Bæþsealfe ','Ciricæw ','Ciricæwe ','Ciricæwa ']},'en-pirate',{'and',['* ','Aye '],'background',['Yo-ho-ho'],'but',['* ','Avast! '],'examples',['Dead men tell no tales'],'feature',['Ahoy matey!'],'given',['* ','Gangway! '],'name','Pirate','native','Pirate','rule',['Rule'],'scenario',['Heave to'],'scenarioOutline',['Shiver me timbers'],'then',['* ','Let go and haul '],'when',['* ','Blimey! ']},'en-tx',{'and',['Come hell or high water '],'background',['Lemme tell y\'all a story'],'but',['Well now hold on, I\'ll you what '],'examples',['Now that\'s a story longer than a cattle drive in July'],'feature',['This ain’t my first rodeo','All gussied up'],'given',['Fixin\' to ','All git out '],'name','Texas','native','Texas','rule',['Rule '],'scenario',['All hat and no cattle'],'scenarioOutline',['Serious as a snake bite','Busy as a hound in flea season'],'then',['There’s no tree but bears some fruit '],'when',['Quick out of the chute ']},'eo',{'and',['* ','Kaj '],'background',['Fono'],'but',['* ','Sed '],'examples',['Ekzemploj'],'feature',['Trajto'],'given',['* ','Donitaĵo ','Komence '],'name','Esperanto','native','Esperanto','rule',['Rule'],'scenario',['Ekzemplo','Scenaro','Kazo'],'scenarioOutline',['Konturo de la scenaro','Skizo','Kazo-skizo'],'then',['* ','Do '],'when',['* ','Se ']},'es',{'and',['* ','Y ','E '],'background',['Antecedentes'],'but',['* ','Pero '],'examples',['Ejemplos'],'feature',['Característica','Necesidad del negocio','Requisito'],'given',['* ','Dado ','Dada ','Dados ','Dadas '],'name','Spanish','native','español','rule',['Regla','Regla de negocio'],'scenario',['Ejemplo','Escenario'],'scenarioOutline',['Esquema del escenario'],'then',['* ','Entonces '],'when',['* ','Cuando ']},'et',{'and',['* ','Ja '],'background',['Taust'],'but',['* ','Kuid '],'examples',['Juhtumid'],'feature',['Omadus'],'given',['* ','Eeldades '],'name','Estonian','native','eesti keel','rule',['Reegel'],'scenario',['Juhtum','Stsenaarium'],'scenarioOutline',['Raamjuhtum','Raamstsenaarium'],'then',['* ','Siis '],'when',['* ','Kui ']},'fa',{'and',['* ','و '],'background',['زمینه'],'but',['* ','اما '],'examples',['نمونه ها'],'feature',['وِیژگی'],'given',['* ','با فرض '],'name','Persian','native','فارسی','rule',['Rule'],'scenario',['مثال','سناریو'],'scenarioOutline',['الگوی سناریو'],'then',['* ','آنگاه '],'when',['* ','هنگامی ']},'fi',{'and',['* ','Ja '],'background',['Tausta'],'but',['* ','Mutta '],'examples',['Tapaukset'],'feature',['Ominaisuus'],'given',['* ','Oletetaan '],'name','Finnish','native','suomi','rule',['Rule'],'scenario',['Tapaus'],'scenarioOutline',['Tapausaihio'],'then',['* ','Niin '],'when',['* ','Kun ']},'fr',{'and',['* ','Et que ','Et qu\'','Et '],'background',['Contexte'],'but',['* ','Mais que ','Mais qu\'','Mais '],'examples',['Exemples'],'feature',['Fonctionnalité'],'given',['* ','Soit ','Sachant que ','Sachant qu\'','Sachant ','Etant donné que ','Etant donné qu\'','Etant donné ','Etant donnée ','Etant donnés ','Etant données ','Étant donné que ','Étant donné qu\'','Étant donné ','Étant donnée ','Étant donnés ','Étant données '],'name','French','native','français','rule',['Règle'],'scenario',['Exemple','Scénario'],'scenarioOutline',['Plan du scénario','Plan du Scénario'],'then',['* ','Alors ','Donc '],'when',['* ','Quand ','Lorsque ','Lorsqu\'']},'ga',{'and',['* ','Agus'],'background',['Cúlra'],'but',['* ','Ach'],'examples',['Samplaí'],'feature',['Gné'],'given',['* ','Cuir i gcás go','Cuir i gcás nach','Cuir i gcás gur','Cuir i gcás nár'],'name','Irish','native','Gaeilge','rule',['Rule'],'scenario',['Sampla','Cás'],'scenarioOutline',['Cás Achomair'],'then',['* ','Ansin'],'when',['* ','Nuair a','Nuair nach','Nuair ba','Nuair nár']},'gj',{'and',['* ','અને '],'background',['બેકગ્રાઉન્ડ'],'but',['* ','પણ '],'examples',['ઉદાહરણો'],'feature',['લક્ષણ','વ્યાપાર જરૂર','ક્ષમતા'],'given',['* ','આપેલ છે '],'name','Gujarati','native','ગુજરાતી','rule',['Rule'],'scenario',['ઉદાહરણ','સ્થિતિ'],'scenarioOutline',['પરિદ્દશ્ય રૂપરેખા','પરિદ્દશ્ય ઢાંચો'],'then',['* ','પછી '],'when',['* ','ક્યારે ']},'gl',{'and',['* ','E '],'background',['Contexto'],'but',['* ','Mais ','Pero '],'examples',['Exemplos'],'feature',['Característica'],'given',['* ','Dado ','Dada ','Dados ','Dadas '],'name','Galician','native','galego','rule',['Rule'],'scenario',['Exemplo','Escenario'],'scenarioOutline',['Esbozo do escenario'],'then',['* ','Entón ','Logo '],'when',['* ','Cando ']},'he',{'and',['* ','וגם '],'background',['רקע'],'but',['* ','אבל '],'examples',['דוגמאות'],'feature',['תכונה'],'given',['* ','בהינתן '],'name','Hebrew','native','עברית','rule',['כלל'],'scenario',['דוגמא','תרחיש'],'scenarioOutline',['תבנית תרחיש'],'then',['* ','אז ','אזי '],'when',['* ','כאשר ']},'hi',{'and',['* ','और ','तथा '],'background',['पृष्ठभूमि'],'but',['* ','पर ','परन्तु ','किन्तु '],'examples',['उदाहरण'],'feature',['रूप लेख'],'given',['* ','अगर ','यदि ','चूंकि '],'name','Hindi','native','हिंदी','rule',['नियम'],'scenario',['परिदृश्य'],'scenarioOutline',['परिदृश्य रूपरेखा'],'then',['* ','तब ','तदा '],'when',['* ','जब ','कदा ']},'hr',{'and',['* ','I '],'background',['Pozadina'],'but',['* ','Ali '],'examples',['Primjeri','Scenariji'],'feature',['Osobina','Mogućnost','Mogucnost'],'given',['* ','Zadan ','Zadani ','Zadano ','Ukoliko '],'name','Croatian','native','hrvatski','rule',['Rule'],'scenario',['Primjer','Scenarij'],'scenarioOutline',['Skica','Koncept'],'then',['* ','Onda '],'when',['* ','Kada ','Kad ']},'ht',{'and',['* ','Ak ','Epi ','E '],'background',['Kontèks','Istorik'],'but',['* ','Men '],'examples',['Egzanp'],'feature',['Karakteristik','Mak','Fonksyonalite'],'given',['* ','Sipoze ','Sipoze ke ','Sipoze Ke '],'name','Creole','native','kreyòl','rule',['Rule'],'scenario',['Senaryo'],'scenarioOutline',['Plan senaryo','Plan Senaryo','Senaryo deskripsyon','Senaryo Deskripsyon','Dyagram senaryo','Dyagram Senaryo'],'then',['* ','Lè sa a ','Le sa a '],'when',['* ','Lè ','Le ']},'hu',{'and',['* ','És '],'background',['Háttér'],'but',['* ','De '],'examples',['Példák'],'feature',['Jellemző'],'given',['* ','Amennyiben ','Adott '],'name','Hungarian','native','magyar','rule',['Szabály'],'scenario',['Példa','Forgatókönyv'],'scenarioOutline',['Forgatókönyv vázlat'],'then',['* ','Akkor '],'when',['* ','Majd ','Ha ','Amikor ']},'id',{'and',['* ','Dan '],'background',['Dasar','Latar Belakang'],'but',['* ','Tapi ','Tetapi '],'examples',['Contoh','Misal'],'feature',['Fitur'],'given',['* ','Dengan ','Diketahui ','Diasumsikan ','Bila ','Jika '],'name','Indonesian','native','Bahasa Indonesia','rule',['Rule','Aturan'],'scenario',['Skenario'],'scenarioOutline',['Skenario konsep','Garis-Besar Skenario'],'then',['* ','Maka ','Kemudian '],'when',['* ','Ketika ']},'is',{'and',['* ','Og '],'background',['Bakgrunnur'],'but',['* ','En '],'examples',['Dæmi','Atburðarásir'],'feature',['Eiginleiki'],'given',['* ','Ef '],'name','Icelandic','native','Íslenska','rule',['Rule'],'scenario',['Atburðarás'],'scenarioOutline',['Lýsing Atburðarásar','Lýsing Dæma'],'then',['* ','Þá '],'when',['* ','Þegar ']},'it',{'and',['* ','E '],'background',['Contesto'],'but',['* ','Ma '],'examples',['Esempi'],'feature',['Funzionalità','Esigenza di Business','Abilità'],'given',['* ','Dato ','Data ','Dati ','Date '],'name','Italian','native','italiano','rule',['Regola'],'scenario',['Esempio','Scenario'],'scenarioOutline',['Schema dello scenario'],'then',['* ','Allora '],'when',['* ','Quando ']},'ja',{'and',['* ','且つ','かつ'],'background',['背景'],'but',['* ','然し','しかし','但し','ただし'],'examples',['例','サンプル'],'feature',['フィーチャ','機能'],'given',['* ','前提'],'name','Japanese','native','日本語','rule',['ルール'],'scenario',['シナリオ'],'scenarioOutline',['シナリオアウトライン','シナリオテンプレート','テンプレ','シナリオテンプレ'],'then',['* ','ならば'],'when',['* ','もし']},'jv',{'and',['* ','Lan '],'background',['Dasar'],'but',['* ','Tapi ','Nanging ','Ananging '],'examples',['Conto','Contone'],'feature',['Fitur'],'given',['* ','Nalika ','Nalikaning '],'name','Javanese','native','Basa Jawa','rule',['Rule'],'scenario',['Skenario'],'scenarioOutline',['Konsep skenario'],'then',['* ','Njuk ','Banjur '],'when',['* ','Manawa ','Menawa ']},'ka',{'and',['* ','და ','ასევე '],'background',['კონტექსტი'],'but',['* ','მაგრამ ','თუმცა '],'examples',['მაგალითები'],'feature',['თვისება','მოთხოვნა'],'given',['* ','მოცემული ','Მოცემულია ','ვთქვათ '],'name','Georgian','native','ქართული','rule',['წესი'],'scenario',['მაგალითად','მაგალითი','მაგ','სცენარი'],'scenarioOutline',['სცენარის ნიმუში','სცენარის შაბლონი','ნიმუში','შაბლონი'],'then',['* ','მაშინ '],'when',['* ','როდესაც ','როცა ','როგორც კი ','თუ ']},'kn',{'and',['* ','ಮತ್ತು '],'background',['ಹಿನ್ನೆಲೆ'],'but',['* ','ಆದರೆ '],'examples',['ಉದಾಹರಣೆಗಳು'],'feature',['ಹೆಚ್ಚಳ'],'given',['* ','ನೀಡಿದ '],'name','Kannada','native','ಕನ್ನಡ','rule',['Rule'],'scenario',['ಉದಾಹರಣೆ','ಕಥಾಸಾರಾಂಶ'],'scenarioOutline',['ವಿವರಣೆ'],'then',['* ','ನಂತರ '],'when',['* ','ಸ್ಥಿತಿಯನ್ನು ']},'ko',{'and',['* ','그리고'],'background',['배경'],'but',['* ','하지만','단'],'examples',['예'],'feature',['기능'],'given',['* ','조건','먼저'],'name','Korean','native','한국어','rule',['Rule'],'scenario',['시나리오'],'scenarioOutline',['시나리오 개요'],'then',['* ','그러면'],'when',['* ','만일','만약']},'lt',{'and',['* ','Ir '],'background',['Kontekstas'],'but',['* ','Bet '],'examples',['Pavyzdžiai','Scenarijai','Variantai'],'feature',['Savybė'],'given',['* ','Duota '],'name','Lithuanian','native','lietuvių kalba','rule',['Rule'],'scenario',['Pavyzdys','Scenarijus'],'scenarioOutline',['Scenarijaus šablonas'],'then',['* ','Tada '],'when',['* ','Kai ']},'lu',{'and',['* ','an ','a '],'background',['Hannergrond'],'but',['* ','awer ','mä '],'examples',['Beispiller'],'feature',['Funktionalitéit'],'given',['* ','ugeholl '],'name','Luxemburgish','native','Lëtzebuergesch','rule',['Rule'],'scenario',['Beispill','Szenario'],'scenarioOutline',['Plang vum Szenario'],'then',['* ','dann '],'when',['* ','wann ']},'lv',{'and',['* ','Un '],'background',['Konteksts','Situācija'],'but',['* ','Bet '],'examples',['Piemēri','Paraugs'],'feature',['Funkcionalitāte','Fīča'],'given',['* ','Kad '],'name','Latvian','native','latviešu','rule',['Rule'],'scenario',['Piemērs','Scenārijs'],'scenarioOutline',['Scenārijs pēc parauga'],'then',['* ','Tad '],'when',['* ','Ja ']},'mk-Cyrl',{'and',['* ','И '],'background',['Контекст','Содржина'],'but',['* ','Но '],'examples',['Примери','Сценарија'],'feature',['Функционалност','Бизнис потреба','Можност'],'given',['* ','Дадено ','Дадена '],'name','Macedonian','native','Македонски','rule',['Rule'],'scenario',['Пример','Сценарио','На пример'],'scenarioOutline',['Преглед на сценарија','Скица','Концепт'],'then',['* ','Тогаш '],'when',['* ','Кога ']},'mk-Latn',{'and',['* ','I '],'background',['Kontekst','Sodrzhina'],'but',['* ','No '],'examples',['Primeri','Scenaria'],'feature',['Funkcionalnost','Biznis potreba','Mozhnost'],'given',['* ','Dadeno ','Dadena '],'name','Macedonian (Latin)','native','Makedonski (Latinica)','rule',['Rule'],'scenario',['Scenario','Na primer'],'scenarioOutline',['Pregled na scenarija','Skica','Koncept'],'then',['* ','Togash '],'when',['* ','Koga ']},'mn',{'and',['* ','Мөн ','Тэгээд '],'background',['Агуулга'],'but',['* ','Гэхдээ ','Харин '],'examples',['Тухайлбал'],'feature',['Функц','Функционал'],'given',['* ','Өгөгдсөн нь ','Анх '],'name','Mongolian','native','монгол','rule',['Rule'],'scenario',['Сценар'],'scenarioOutline',['Сценарын төлөвлөгөө'],'then',['* ','Тэгэхэд ','Үүний дараа '],'when',['* ','Хэрэв ']},'mr',{'and',['* ','आणि ','तसेच '],'background',['पार्श्वभूमी'],'but',['* ','पण ','परंतु '],'examples',['उदाहरण'],'feature',['वैशिष्ट्य','सुविधा'],'given',['* ','जर','दिलेल्या प्रमाणे '],'name','Marathi','native','मराठी','rule',['नियम'],'scenario',['परिदृश्य'],'scenarioOutline',['परिदृश्य रूपरेखा'],'then',['* ','मग ','तेव्हा '],'when',['* ','जेव्हा ']},'ne',{'and',['* ','र ','अनि '],'background',['पृष्ठभूमी'],'but',['* ','तर '],'examples',['उदाहरण','उदाहरणहरु'],'feature',['सुविधा','विशेषता'],'given',['* ','दिइएको ','दिएको ','यदि '],'name','Nepali','native','नेपाली','rule',['नियम'],'scenario',['परिदृश्य'],'scenarioOutline',['परिदृश्य रूपरेखा'],'then',['* ','त्यसपछि ','अनी '],'when',['* ','जब ']},'nl',{'and',['* ','En '],'background',['Achtergrond'],'but',['* ','Maar '],'examples',['Voorbeelden'],'feature',['Functionaliteit'],'given',['* ','Gegeven ','Stel '],'name','Dutch','native','Nederlands','rule',['Rule'],'scenario',['Voorbeeld','Scenario'],'scenarioOutline',['Abstract Scenario'],'then',['* ','Dan '],'when',['* ','Als ','Wanneer ']},'no',{'and',['* ','Og '],'background',['Bakgrunn'],'but',['* ','Men '],'examples',['Eksempler'],'feature',['Egenskap'],'given',['* ','Gitt '],'name','Norwegian','native','norsk','rule',['Regel'],'scenario',['Eksempel','Scenario'],'scenarioOutline',['Scenariomal','Abstrakt Scenario'],'then',['* ','Så '],'when',['* ','Når ']},'pa',{'and',['* ','ਅਤੇ '],'background',['ਪਿਛੋਕੜ'],'but',['* ','ਪਰ '],'examples',['ਉਦਾਹਰਨਾਂ'],'feature',['ਖਾਸੀਅਤ','ਮੁਹਾਂਦਰਾ','ਨਕਸ਼ ਨੁਹਾਰ'],'given',['* ','ਜੇਕਰ ','ਜਿਵੇਂ ਕਿ '],'name','Panjabi','native','ਪੰਜਾਬੀ','rule',['Rule'],'scenario',['ਉਦਾਹਰਨ','ਪਟਕਥਾ'],'scenarioOutline',['ਪਟਕਥਾ ਢਾਂਚਾ','ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ'],'then',['* ','ਤਦ '],'when',['* ','ਜਦੋਂ ']},'pl',{'and',['* ','Oraz ','I '],'background',['Założenia'],'but',['* ','Ale '],'examples',['Przykłady'],'feature',['Właściwość','Funkcja','Aspekt','Potrzeba biznesowa'],'given',['* ','Zakładając ','Mając ','Zakładając, że '],'name','Polish','native','polski','rule',['Zasada','Reguła'],'scenario',['Przykład','Scenariusz'],'scenarioOutline',['Szablon scenariusza'],'then',['* ','Wtedy '],'when',['* ','Jeżeli ','Jeśli ','Gdy ','Kiedy ']},'pt',{'and',['* ','E '],'background',['Contexto','Cenário de Fundo','Cenario de Fundo','Fundo'],'but',['* ','Mas '],'examples',['Exemplos','Cenários','Cenarios'],'feature',['Funcionalidade','Característica','Caracteristica'],'given',['* ','Dado ','Dada ','Dados ','Dadas '],'name','Portuguese','native','português','rule',['Regra'],'scenario',['Exemplo','Cenário','Cenario'],'scenarioOutline',['Esquema do Cenário','Esquema do Cenario','Delineação do Cenário','Delineacao do Cenario'],'then',['* ','Então ','Entao '],'when',['* ','Quando ']},'ro',{'and',['* ','Si ','Și ','Şi '],'background',['Context'],'but',['* ','Dar '],'examples',['Exemple'],'feature',['Functionalitate','Funcționalitate','Funcţionalitate'],'given',['* ','Date fiind ','Dat fiind ','Dată fiind','Dati fiind ','Dați fiind ','Daţi fiind '],'name','Romanian','native','română','rule',['Rule'],'scenario',['Exemplu','Scenariu'],'scenarioOutline',['Structura scenariu','Structură scenariu'],'then',['* ','Atunci '],'when',['* ','Cand ','Când ']},'ru',{'and',['* ','И ','К тому же ','Также '],'background',['Предыстория','Контекст'],'but',['* ','Но ','А ','Иначе '],'examples',['Примеры'],'feature',['Функция','Функциональность','Функционал','Свойство','Фича'],'given',['* ','Допустим ','Дано ','Пусть '],'name','Russian','native','русский','rule',['Правило'],'scenario',['Пример','Сценарий'],'scenarioOutline',['Структура сценария','Шаблон сценария'],'then',['* ','То ','Затем ','Тогда '],'when',['* ','Когда ','Если ']},'sk',{'and',['* ','A ','A tiež ','A taktiež ','A zároveň '],'background',['Pozadie'],'but',['* ','Ale '],'examples',['Príklady'],'feature',['Požiadavka','Funkcia','Vlastnosť'],'given',['* ','Pokiaľ ','Za predpokladu '],'name','Slovak','native','Slovensky','rule',['Rule'],'scenario',['Príklad','Scenár'],'scenarioOutline',['Náčrt Scenáru','Náčrt Scenára','Osnova Scenára'],'then',['* ','Tak ','Potom '],'when',['* ','Keď ','Ak ']},'sl',{'and',['In ','Ter '],'background',['Kontekst','Osnova','Ozadje'],'but',['Toda ','Ampak ','Vendar '],'examples',['Primeri','Scenariji'],'feature',['Funkcionalnost','Funkcija','Možnosti','Moznosti','Lastnost','Značilnost'],'given',['Dano ','Podano ','Zaradi ','Privzeto '],'name','Slovenian','native','Slovenski','rule',['Rule'],'scenario',['Primer','Scenarij'],'scenarioOutline',['Struktura scenarija','Skica','Koncept','Oris scenarija','Osnutek'],'then',['Nato ','Potem ','Takrat '],'when',['Ko ','Ce ','Če ','Kadar ']},'sr-Cyrl',{'and',['* ','И '],'background',['Контекст','Основа','Позадина'],'but',['* ','Али '],'examples',['Примери','Сценарији'],'feature',['Функционалност','Могућност','Особина'],'given',['* ','За дато ','За дате ','За дати '],'name','Serbian','native','Српски','rule',['Правило'],'scenario',['Пример','Сценарио','Пример'],'scenarioOutline',['Структура сценарија','Скица','Концепт'],'then',['* ','Онда '],'when',['* ','Када ','Кад ']},'sr-Latn',{'and',['* ','I '],'background',['Kontekst','Osnova','Pozadina'],'but',['* ','Ali '],'examples',['Primeri','Scenariji'],'feature',['Funkcionalnost','Mogućnost','Mogucnost','Osobina'],'given',['* ','Za dato ','Za date ','Za dati '],'name','Serbian (Latin)','native','Srpski (Latinica)','rule',['Pravilo'],'scenario',['Scenario','Primer'],'scenarioOutline',['Struktura scenarija','Skica','Koncept'],'then',['* ','Onda '],'when',['* ','Kada ','Kad ']},'sv',{'and',['* ','Och '],'background',['Bakgrund'],'but',['* ','Men '],'examples',['Exempel'],'feature',['Egenskap'],'given',['* ','Givet '],'name','Swedish','native','Svenska','rule',['Regel'],'scenario',['Scenario'],'scenarioOutline',['Abstrakt Scenario','Scenariomall'],'then',['* ','Så '],'when',['* ','När ']},'ta',{'and',['* ','மேலும் ','மற்றும் '],'background',['பின்னணி'],'but',['* ','ஆனால் '],'examples',['எடுத்துக்காட்டுகள்','காட்சிகள்','நிலைமைகளில்'],'feature',['அம்சம்','வணிக தேவை','திறன்'],'given',['* ','கொடுக்கப்பட்ட '],'name','Tamil','native','தமிழ்','rule',['Rule'],'scenario',['உதாரணமாக','காட்சி'],'scenarioOutline',['காட்சி சுருக்கம்','காட்சி வார்ப்புரு'],'then',['* ','அப்பொழுது '],'when',['* ','எப்போது ']},'te',{'and',['* ','మరియు '],'background',['నేపథ్యం'],'but',['* ','కాని '],'examples',['ఉదాహరణలు'],'feature',['గుణము'],'given',['* ','చెప్పబడినది '],'name','Telugu','native','తెలుగు','rule',['Rule'],'scenario',['ఉదాహరణ','సన్నివేశం'],'scenarioOutline',['కథనం'],'then',['* ','అప్పుడు '],'when',['* ','ఈ పరిస్థితిలో ']},'th',{'and',['* ','และ '],'background',['แนวคิด'],'but',['* ','แต่ '],'examples',['ชุดของตัวอย่าง','ชุดของเหตุการณ์'],'feature',['โครงหลัก','ความต้องการทางธุรกิจ','ความสามารถ'],'given',['* ','กำหนดให้ '],'name','Thai','native','ไทย','rule',['Rule'],'scenario',['เหตุการณ์'],'scenarioOutline',['สรุปเหตุการณ์','โครงสร้างของเหตุการณ์'],'then',['* ','ดังนั้น '],'when',['* ','เมื่อ ']},'tlh',{'and',['* ','\'ej ','latlh '],'background',['mo\''],'but',['* ','\'ach ','\'a '],'examples',['ghantoH','lutmey'],'feature',['Qap','Qu\'meH \'ut','perbogh','poQbogh malja\'','laH'],'given',['* ','ghu\' noblu\' ','DaH ghu\' bejlu\' '],'name','Klingon','native','tlhIngan','rule',['Rule'],'scenario',['lut'],'scenarioOutline',['lut chovnatlh'],'then',['* ','vaj '],'when',['* ','qaSDI\' ']},'tr',{'and',['* ','Ve '],'background',['Geçmiş'],'but',['* ','Fakat ','Ama '],'examples',['Örnekler'],'feature',['Özellik'],'given',['* ','Diyelim ki '],'name','Turkish','native','Türkçe','rule',['Kural'],'scenario',['Örnek','Senaryo'],'scenarioOutline',['Senaryo taslağı'],'then',['* ','O zaman '],'when',['* ','Eğer ki ']},'tt',{'and',['* ','Һәм ','Вә '],'background',['Кереш'],'but',['* ','Ләкин ','Әмма '],'examples',['Үрнәкләр','Мисаллар'],'feature',['Мөмкинлек','Үзенчәлеклелек'],'given',['* ','Әйтик '],'name','Tatar','native','Татарча','rule',['Rule'],'scenario',['Сценарий'],'scenarioOutline',['Сценарийның төзелеше'],'then',['* ','Нәтиҗәдә '],'when',['* ','Әгәр ']},'uk',{'and',['* ','І ','А також ','Та '],'background',['Передумова'],'but',['* ','Але '],'examples',['Приклади'],'feature',['Функціонал'],'given',['* ','Припустимо ','Припустимо, що ','Нехай ','Дано '],'name','Ukrainian','native','Українська','rule',['Rule'],'scenario',['Приклад','Сценарій'],'scenarioOutline',['Структура сценарію'],'then',['* ','То ','Тоді '],'when',['* ','Якщо ','Коли ']},'ur',{'and',['* ','اور '],'background',['پس منظر'],'but',['* ','لیکن '],'examples',['مثالیں'],'feature',['صلاحیت','کاروبار کی ضرورت','خصوصیت'],'given',['* ','اگر ','بالفرض ','فرض کیا '],'name','Urdu','native','اردو','rule',['Rule'],'scenario',['منظرنامہ'],'scenarioOutline',['منظر نامے کا خاکہ'],'then',['* ','پھر ','تب '],'when',['* ','جب ']},'uz',{'and',['* ','Ва '],'background',['Тарих'],'but',['* ','Лекин ','Бирок ','Аммо '],'examples',['Мисоллар'],'feature',['Функционал'],'given',['* ','Belgilangan '],'name','Uzbek','native','Узбекча','rule',['Rule'],'scenario',['Сценарий'],'scenarioOutline',['Сценарий структураси'],'then',['* ','Унда '],'when',['* ','Агар ']},'vi',{'and',['* ','Và '],'background',['Bối cảnh'],'but',['* ','Nhưng '],'examples',['Dữ liệu'],'feature',['Tính năng'],'given',['* ','Biết ','Cho '],'name','Vietnamese','native','Tiếng Việt','rule',['Rule'],'scenario',['Tình huống','Kịch bản'],'scenarioOutline',['Khung tình huống','Khung kịch bản'],'then',['* ','Thì '],'when',['* ','Khi ']},'zh-CN',{'and',['* ','而且','并且','同时'],'background',['背景'],'but',['* ','但是'],'examples',['例子'],'feature',['功能'],'given',['* ','假如','假设','假定'],'name','Chinese simplified','native','简体中文','rule',['Rule','规则'],'scenario',['场景','剧本'],'scenarioOutline',['场景大纲','剧本大纲'],'then',['* ','那么'],'when',['* ','当']},'zh-TW',{'and',['* ','而且','並且','同時'],'background',['背景'],'but',['* ','但是'],'examples',['例子'],'feature',['功能'],'given',['* ','假如','假設','假定'],'name','Chinese traditional','native','繁體中文','rule',['Rule'],'scenario',['場景','劇本'],'scenarioOutline',['場景大綱','劇本大綱'],'then',['* ','那麼'],'when',['* ','當']}};
1;

As a result, when multiple contributors submit changes to gherkin-languages.json their PR's will always conflict. Because PRs are not often looked at this happens more often then you'd think.

✨ Do you have a proposal for making it better?

Consider changing build_languages.pl so it generates the file with some formatting.

go: Can't upgrade messages

🤔 What's the problem you've observed?

Trying to upgrade the messages used in Gherkin I run into this problem:

The released code sits in a sub directory named go that has been tagged go/v21.0.1 here https://github.com/cucumber/messages/tree/go/v21.0.1/go. When I try to require this using:

require (
	github.com/cucumber/messages/go/v21 v21.0.1
)

And then go get I got:

go: github.com/cucumber/messages/go/[email protected]: verifying go.mod: github.com/cucumber/messages/go/[email protected]/go.mod: reading https://sum.golang.org/lookup/github.com/cucumber/messages/go/[email protected]: 404 Not Found
        server response: not found: github.com/cucumber/messages/go/[email protected]: invalid version: unknown revision go/v21.0.1

Tagging with v21.0.1 also doesn't work.

Encourage Markdown syntax in Gherkin?

The idea

On a recent contributors call it was discussed that some teams, and some tooling in the wild, already treats elements of Gherkin as Markdown.

I've definitely seen usages of:

  • Bullet lists
  • Emphasis with asterisks/underscores

What would be the benefits?

Being clear about Markdown flavour would aid interoperability

Recognising that Markdown is ok would encourage more elaborate usage, and encourage the tooling that doesn't currently treat it as markdown to start to do so - for instance Github could probably trivially improve how features are presented.

Some interesting ones that occur:

  • More use of tables
  • More use of hyperlinks
  • More use of embedded images
  • More use of embedded non-text formats (e.g. embed some GraphViz?)

What would supporting it look like?

We would potentially want to

  1. Make it clear in docs which elements this applies to (e.g. in Feature/Rule/Example descriptions, but not in their names, probably not in scenario steps?)
  2. Nominate a flavour of Markdown
  3. Add gherkin testdata that contains complex markdown (e.g. do the 3-backticks collide with our docstring delimiters?)

What are the arguments against it?

There is already work being done by @aslakhellesoy to enable features-in-markdown, this may complicate or confuse the messaging.

The complexity of how tool authors and teams are using descriptions is their responsibility and we shouldn't peer into the formats being used.

There's a can of worms here

Gherkin testdata duplication

🤔 What's the problem you've observed?

Testdata for gherkin are duplicated into each implementation. In case of update of the testdata, it generates huge diffs which are making PRs difficult to review properly (cf. cucumber/common#1741)

✨ Do you have a proposal for making it better?

Stop duplicating testdata and refer to those using relative paths
Or at least duplicating the testdata during the build, but ignoring those from the repo

📚 Any additional context?

Why the purpose of the duplication? Is it because of the subrepos?


This text was originally generated from a template, then edited by hand. You can modify the template here.

Dependabot config

Trying to configure dependabot to do dependency upgrade PRs for ruby

Build gherkin/dart

The new gherkin/dart module is not built in CI.

When cucumber/common#1630 was merged we forgot to add a job to .circleci/config.yml, so it isn't built as a separate job. There is nothing in gherkin/Makefile either, so the module isn't built as part of the serial job either.

/cc @mattwynne @aurelien-reeves

dart: Parser is nog generated using Berp

🤔 What's the problem you've observed?

The Gherkin Parser for Dart is not generated using Berp. This is a problem because:

As of May 2016 Gherkin is implemented in 8 languages. This number is likely to increase to a dozen within a year or two. Very few programmers are intimate with all those languages. Therefore, in order to make it as easy as possible to refactor, fix bugs, add features and release packages it is essential that all implementations have a similar structure.

CONTRIBUTING.md - consistency between implementations

✨ Do you have a proposal for making it better?

Either:

  • Use Berp to generate the parser.
  • Remove Dart.

📚 Any additional context?

There are no acceptance tests for the Dart parser implementation #30

java: Rewrite Groovy code generation to Java

🤔 What's the problem you've observed?

The Java module generates the Gherkin Dialects using a Groovy script.

Unfortunately the groovy-maven-plugin doesn't support Java 17 source code yet (groovy/gmaven#28). While we currently only have to run on Java 17 for cucumber/cucumber-jvm#2644 it is not unimaginable that at some point in the future we'll also want to compile our own source code with 17 as well.

✨ Do you have a proposal for making it better?

With the increased release cadence of Java it would be prudent to keep the technology stack shallow and remove the dependency on Groovy and Groovy related components al together. So replacing the whole stack with pure Java would be beneficial.

📚 Any additional context?

This can effectively be solved in the same way as cucumber/cucumber-jvm#2648.

objective-c: Is not build in CI and does not follow the repository template

🤔 What's the problem you've observed?

Currently Objective-C is not build in CI and does not fully implement the acceptance test suite.

Compare:

.compared: .built $(TOKENS)
#.compared: .built $(TOKENS) $(ASTS) $(ERRORS)

Against:

acceptance: .built $(TOKENS) $(ASTS) $(PICKLES) $(ERRORS) $(SOURCES) ## Build acceptance test dir and compare results with reference

This is a problem because:

As of May 2016 Gherkin is implemented in 8 languages. This number is likely to increase to a dozen within a year or two. Very few programmers are intimate with all those languages. Therefore, in order to make it as easy as possible to refactor, fix bugs, add features and release packages it is essential that all implementations have a similar structure.

CONTRIBUTING.md - consistency between implementations

✨ Do you have a proposal for making it better?

Either

  • Remove objective-c from the list of supported implementations
  • Fix the build process

📚 Any additional context?

The objective-c project was already not build in CI while in the common repo. I would be surprised if it even works.

Consider adding `After` as keyword to the Gherkin syntax

🤔 What's the problem you're trying to solve?

Even though Cucumber itself provides hooks to clean up any mess created by every test, I'm missing a simple solution
to tidy up some leftovers of a special test case.

99% percent of our test behave in a good manner and don't leave anything behind or the app in question in a bad shape
however, there are a few tests that require a cleaning crew.

ATM we just add a And/Then step to the end of the scenario

✨ What's your proposed solution?

Adding an AFTER step to the Gherkin keywords that behaves as Background just after a scenario is finished.

⛏ Have you considered any alternatives or workarounds?

Yes, using the after* hooks with much extra logic to determine if the hook is even needed to execute.

📚 Any additional context?

Dunno yet, let me know if you need more.

PS. Adding the keyword is not the end of the story as all the different language implementations of parsing and executing Gherkin need to support it as well, but I thought this is the best place to start.

Thx

java: bad performance in StringUtils

👓 What did you see?

There are performance issues in https://github.com/cucumber/gherkin/blob/main/java/src/main/java/io/cucumber/gherkin/StringUtils.java because the String.replaceAll method used in the StringUtils class makes a new Pattern.compile at every call.

The impact is that on a project with ~150 teststeps and ~400 test scenarios, the feature parser uses 0.68% of the total CPU time in the StringUtils.trim() method (about 50 ms). That's not a lot, but the still worth the investment effort.

✅ What did you expect to see?

I expect the performance StringUtils methods to run faster. It's easy to do so by precompiling the Pattern :

Method Description ops/s
StringUtilsBenchmark.trim0 original version 1'162'751 ± 74'322
StringUtilsBenchmark.trim1 precomputed Pattern.compile 3'861'664 ± 87'344

📦 Which tool/library version are you using?

Cucumber 7.10.1

🔬 How could we reproduce it?

Steps to reproduce the behavior:

  1. Create a Maven project with the following dependencies:

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit-platform-engine</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-picocontainer</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
       <groupId>org.openjdk.jmh</groupId>
       <artifactId>jmh-generator-annprocess</artifactId>
       <version>1.36</version>
       <scope>test</scope>
    </dependency>
    
  2. Run the JMH benchmark from
    gherkin.zip

perl: Acceptance tests do not include parse errors

🤔 What's the problem you've observed?

Currently the error set of tokens is not included in the acceptance tests.

acceptance: .built $(TOKENS) $(ASTS) $(PICKLES) $(SOURCES) #$(ERRORS) ## Build acceptance test dir and compare results with reference

This is a problem because:

As of May 2016 Gherkin is implemented in 8 languages. This number is likely to increase to a dozen within a year or two. Very few programmers are intimate with all those languages. Therefore, in order to make it as easy as possible to refactor, fix bugs, add features and release packages it is essential that all implementations have a similar structure.

CONTRIBUTING.md - consistency between implementations

✨ Do you have a proposal for making it better?

Fix the acceptance tests to include the parse errors.

Pickle compiled without error from AST containing invalid example data

👓 What did you see? - Pickle compiled without error from AST containing invalid example data

✅ What did you expect to see? - Pickle compilation fails on invalid incoming data from AST

📦 Which tool/library version are you using? - https://pypi.org/project/gherkin-official/23.0.1/

🔬 How could we reproduce it?

from gherkin.parser import Parser
from gherkin.pickles.compiler import Compiler

feature = """\
Feature: Outline
    Scenario Outline: Outlined with duplicated parameter example table
         Given there are <start> cucumbers
         When I eat <eat> cucumbers
         Then I should have <left> cucumbers

          Examples:
            | start | start | left |
            |   12  |   10  |   7  |
            |    2  |    1  |   1  |
"""

gherkin_ast_data = Parser().parse(feature)
gherkin_ast_data["uri"]='uri'
try:
    pickles_data = Compiler().compile(gherkin_ast_data)
except Exception:
    pass
else:
    raise RuntimeError('Pickles were loaded and are broken')

📚 Any additional context?


This text was originally generated from a template, then edited by hand. You can modify the template here.

[cucumber/gherkin] - comments in feature description cause a parse error

Summary

It looks like comments in any part of the feature description are currently disallowed:

Feature: Using a comment in feature description

  # comment 1
  This is the feature description
  # comment 2

  Example: A normal example

Current Behavior

The text line that comprises the feature description is not allowed to follow the comment 1 so a parse error is thrown. The comment 2 is allowed because it's followed by an Example, so if only comment 1 is removed the file parses correctly.

(4:3): expected: #EOF, #Comment, #BackgroundLine, #TagLine, #ScenarioLine, #RuleLine, #Empty, got '  This is the feature description'

Context & Motivation

I'm generally looking at where comments are allowed by the parser for behat compatibility and this came up

Your Environment

  • Version used: Go gherkin binary, 17.0.2 darwin amd64
  • Operating System and version: macOS Big Sur (M1)

javascript: Acceptance tests do not include tokens

🤔 What's the problem you've observed?

The acceptance tests for Javascript currently do verify if the parser produces the right tokens:

ASTS = $(patsubst ../testdata/%,acceptance/testdata/%.ast.ndjson,$(GOOD_FEATURE_FILES))
PICKLES = $(patsubst ../testdata/%,acceptance/testdata/%.pickles.ndjson,$(GOOD_FEATURE_FILES))
SOURCES = $(patsubst ../testdata/%,acceptance/testdata/%.source.ndjson,$(GOOD_FEATURE_FILES))
ERRORS = $(patsubst ../testdata/%,acceptance/testdata/%.errors.ndjson,$(BAD_FEATURE_FILES))

acceptance: .built $(TOKENS) $(ASTS) $(PICKLES) $(ERRORS) $(SOURCES) ## Build acceptance test dir and compare results with reference

Compare with:

gherkin/java/Makefile

Lines 13 to 17 in 1cc2ef0

TOKENS = $(patsubst ../testdata/%,acceptance/testdata/%.tokens,$(GOOD_FEATURE_FILES))
ASTS = $(patsubst ../testdata/%,acceptance/testdata/%.ast.ndjson,$(GOOD_FEATURE_FILES))
PICKLES = $(patsubst ../testdata/%,acceptance/testdata/%.pickles.ndjson,$(GOOD_FEATURE_FILES))
SOURCES = $(patsubst ../testdata/%,acceptance/testdata/%.source.ndjson,$(GOOD_FEATURE_FILES))
ERRORS = $(patsubst ../testdata/%,acceptance/testdata/%.errors.ndjson,$(BAD_FEATURE_FILES))

acceptance: .built $(TOKENS) $(ASTS) $(PICKLES) $(ERRORS) $(SOURCES) ## Build acceptance test dir and compare results with reference

This is a problem because:

As of May 2016 Gherkin is implemented in 8 languages. This number is likely to increase to a dozen within a year or two. Very few programmers are intimate with all those languages. Therefore, in order to make it as easy as possible to refactor, fix bugs, add features and release packages it is essential that all implementations have a similar structure.

CONTRIBUTING.md - consistency between implementations

✨ Do you have a proposal for making it better?

Include the tokens in the acceptance tests again.

📚 Any additional context?

The tokens were removed with cucumber/common#448 and never put back once reverted.

Maximum parse errors that the parser will output

Currently both Java and PHP cap the number of errors at 11 (this maybe was meant to be 10 but I copied Java!) I imagine some others do to?

This is not really reflected in the testdata - I think we should have a document in there with ~20 errors and some pickle parseErrors showing it's capped off

OR we should remove the (arbitrary?) cap...

gherkin: Duplicate keywords in translations

Summary

In Behat/Gherkin we use the cucumber i18n data for translations. We have some tests that use this data to:

  • Generate a gherkin string using the different variations of the keywords
  • Generate a parsed AST that corresponds to that feature
  • Check the parser creates a similar AST when consuming the gherkin

This tends to fail when there are duplicate keywords inside a language's translation, so we skip some languages when doing this test.

Currently we are excluding the following from the tests:

  • ne: अनी means both And and Given
  • uz: Агар means both Given and When
  • en-old: Tha means both When and Then

Impact

Aside from failing tests easily skipped, in Behat our AST retains the 'type' of the node, which in some cases will now be wrong vs what the author intended

Maybe more importantly, in those languages there is a word that means two different things. This may damage education efforts around the G/W/T structure.

Possible Solution

  1. fix the languages listed above to be unambiguous - this would have backwards compatibility issues so might not be acceptable
  2. ensure via automated tests that duplicated words cannot be added to new or existing translations

Deprecate old nuget packages

Hi,

Now we have a lot of old nuget packages, starting from 2011 year.
Now nuget have depreciation feature.
I've propose to do following actions:

  1. Mark as depricated all packages before 6.0.0
  2. Mark as depricated all beta\rc packages (non-release version) and unlist them (they will be hidden on search UI, but still available)

Motivation:
Nuget will have depreciation warning during restore + warning icon in search window in package explorer.
Because this versions are outdated this is good mechanism ask people to migrate to never and supported versions

Nuget package link: https://www.nuget.org/packages/gherkin/#versions-body-tab

Version Downloads Last updated    
26.0.1 0 3 hours ago    
26.0.0 0 4 hours ago    
25.0.2 11,248 a month ago    
25.0.1 1,930 a month ago    
25.0.0 136 a month ago    
24.1.0 10,844 2 months ago    
23.0.1 122,505 9 months ago    
23.0.0 2,042 9 months ago    
22.0.0 181,995 23/09/2021    
20.0.1 59,966 19/07/2021    
20.0.0 3,564 08/07/2021    
19.0.3 7,560,194 24/05/2021    
19.0.2 3,909 19/05/2021    
6.0.0 14,422,703 25/03/2019    
6.0.0-beta1 239,546 22/11/2018    
5.1.0 123,796 30/05/2018    
5.0.0 260,800 13/10/2017    
4.1.4-rc1 1,272 04/10/2017    
4.0.0 50,049 10/04/2016    
3.2.0 5,589 12/01/2016    
3.1.2 9,580 03/10/2015    
3.1.1 1,601 03/09/2015    
3.1.0 1,787 15/08/2015    
2.12.2 2,154 12/10/2013    
2.12.1 1,682 10/08/2013    
2.12.0 1,523 21/04/2013    
2.11.8 1,431 09/04/2013    
2.11.7 1,457 05/04/2013    
2.11.6 1,499 29/01/2013    
2.11.5 1,702 14/10/2012    
2.11.4 1,567 09/10/2012    
2.11.3 1,638 08/10/2012    
2.11.2 1,604 17/08/2012    
2.11.1 1,504 23/06/2012    
2.11.0 1,545 08/06/2012    
2.10.0 1,505 07/05/2012    
2.9.3 1,537 26/03/2012    
2.9.2 1,599 26/03/2012    
2.9.1 1,538 16/03/2012    
2.9.0 2,367 20/02/2012    
2.8.0 1,489 18/02/2012    
2.7.7 2,142 08/02/2012    
2.7.6 1,593 25/01/2012    
2.7.5 1,552 25/01/2012    
2.7.4 1,565 20/01/2012    
2.7.3 1,610 12/01/2012    
2.7.2 1,564 05/01/2012    
2.7.1 1,580 10/12/2011    
2.6.9 1,586 03/12/2011    
2.6.8 1,598 23/11/2011    
2.6.7 1,587 22/11/2011    
2.6.6 6,247 19/11/2011

French equivalent of `Given` is invariable

🤔 What's the problem you're trying to solve?

The equivalent of Given in French is invariable. It should be Etant donné or Etant donné que only.

✨ What's your proposed solution?

Remove all existing sentences, other than Etant donné and Etant donné que:

  • Etant donnée
  • Etant données
  • Etant donnés

⛏ Have you considered any alternatives or workarounds?

Let people write French like they want, but that would be direspectful for the language.


This text was originally generated from a template, then edited by hand. You can modify the template here.

gherkin: Having a Comment before a description breaks parsing

Summary

The documentation states

"Comments are only permitted at the start of a new line, anywhere in the feature file. They begin with zero or more spaces, followed by a hash sign (#) and some text."

However, placing a comment before an element's description is not considered syntactically valid by the (Ruby) parser.

Expected Behavior

The following Gherkin would parse without error:

Feature:

  # TODO: make this not break
  description

Current Behavior

The parser throws an exception

sandbox/features/test.feature: (4:3): expected: #EOF, #Comment, #BackgroundLine, #TagLine, #ScenarioLine, #RuleLine, #Empty, got 'description' (Cucumber::Core::Gherkin::ParseError)

If the comment line is removed, the file parses without error.

Possible Solution

Fix the parser so that it matches the requirements/documentation.

Steps to Reproduce (for bugs)

  1. Make a .feature file with the following text
Feature:

  # TODO: make this not break
  description
  1. Have Cucumber try to run that feature file
  2. See the parsing error

Context & Motivation

Feature files are source code of a sort. As such, comments may be useful/needed on any arbitrary line in the file.

Your Environment

  • Version used: cucumber-gherkin Ruby gem, 14.0.1
  • Operating System and version: Windows 10

Gherkin quitely ignores unfinished table cells

The following is a valid gherkin document with two empty tables according to the gherkin/java 18.1.1 parser. However at a glance the tables do not look empty.

Feature: Empty tables?
  Scenario: This is valid Gherkin
    Given a non-empty list
      | hello 
Feature: Empty tables?
  Scenario Outline: This is also valid Gherkin
    Given a step <hello>
    Examples: 
      | hello 

For more complex tables this will confuse users about what their tables actually contain. This can be especially insidious when tables are automatically transformed into POJO's and used as DTOs. It also has knock on effects on other parts of Cucumber. For example in this SO question, the user is confused about incorrect step definitions generated by ignoring the unfinished table cell.

It is essential that a users are not mislead about the contents of a table. So when encountering an unfinished table cell, i.e. any non-whitespace characters after the last | on a table row line I would expect the parser to throw an exception and explain the problem.

import io.cucumber.gherkin.Gherkin;
import io.cucumber.messages.Messages;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static io.cucumber.gherkin.Gherkin.makeSourceEnvelope;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;

class FeatureParserTest {

    @Test
    void non_empty_table() {
        String source = "" +
                "Feature: Empty table?\n" +
                "  Scenario: This is valid Gherkin\n" +
                "    Given a non-empty list\n" +
                "      | hello \n";

        Messages.PickleStepArgument.PickleTable pickleTable = Gherkin.fromSources(
                singletonList(makeSourceEnvelope(source, "table.feature")),
                false,
                false,
                true,
                () -> UUID.randomUUID().toString()
        )
                .map(Messages.Envelope::getPickle)
                .map(pickle -> pickle.getSteps(0))
                .map(Messages.Pickle.PickleStep::getArgument)
                .map(Messages.PickleStepArgument::getDataTable)
                .findFirst()
                .get();

        assertEquals(1, pickleTable.getRowsList().size());
        assertEquals(1, pickleTable.getRows(0).getCellsCount()); // fails, table is empty
    }

    @Test
    void one_example() {
        String source = "" +
                "Feature: Single example?\n" +
                "  Scenario Outline: This is valid Gherkin\n" +
                "    Given a step <hello>\n" +
                "    Examples: \n" +
                "      | hello \n";

        Messages.GherkinDocument.Feature.TableRow row = Gherkin.fromSources(
                singletonList(makeSourceEnvelope(source, "table.feature")),
                false,
                true,
                false,
                () -> UUID.randomUUID().toString()
        )
                .filter(Messages.Envelope::hasGherkinDocument)
                .map(Messages.Envelope::getGherkinDocument)
                .map(Messages.GherkinDocument::getFeature)
                .map(feature -> feature.getChildren(0))
                .map(Messages.GherkinDocument.Feature.FeatureChild::getScenario)
                .map(Messages.GherkinDocument.Feature.Scenario::getExamplesList)
                .map(examples -> examples.get(0))
                .map(Messages.GherkinDocument.Feature.Scenario.Examples::getTableHeader)
                .findFirst()
                .get();

        assertEquals(1, row.getCellsCount());  // fails, table is empty
    }

}

'And' keyword is not working, on commenting 'And' line the test works!

What did you see? 👀

And keyword is not working, on comment And line the test works!

What did you expect to see? 😎

And keyword should also work like other keywords

Which version are you using? 🎁

io.cucumber cucumber-java 7.2.3 test io.cucumber cucumber-core 7.2.3 io.cucumber cucumber-testng 7.2.3 ## How could we reproduce it? 🔬

Use cucumber with java and testng

image

Update Gherkin syntax highlighters to support Rule keyword

With the release of Gherkin 8 and Cucumbers using it, various syntax highlighters must be updated to support the new keywords.

A good start is to create issues in these tools' bug trackers. The issues should suggest using gherkin-languages.json to do code-generation. That way the lexers/parsers can be easily updated when new translations are added (or if we make other grammar changes in the future).

I have compiled a list of highlighters/editors below. Please add a comment with a link to the issue/PR if you create one and I will update this list. We'll check the box when an issue is fixed.

  • Ace
  • CodeMirror
  • Emacs
  • Geany
  • gherkin-lint
  • Highlight.js
  • IntelliJ IDEA
  • Prism.js
  • Pygments
  • Rainbow
  • SHJS
  • Source Highlight
  • SpecFlow.VisualStudio
  • SyntaxHighlighter
  • Vim
  • Visual Studio Code
  • Sublime Text
  • TextMate
  • GitHub Pull Requests

Which ones did I forget?

gherkin: Compiling empty scenarios

Summary

Currently, the Gherkin pickles compiler removes Gherkin scenarios that don't have any steps, so they don't appear as test cases.

I understand why this was done - what's the point in running a test case that isn't going to test anything? - yet I think we're missing a thing here.

When I watch teams do BDD, they very often start out by creating just the headline or title of a scenario, and defer filling out the Given/When/Then steps until later. I'd like it if Cucumber were reporting that scenario's status as undefined. In order to do this, we'd need to pass a pickle out of the compiler.

Expected Behavior

Pickles compiler outputs pickles (with no steps) for scenarios with no steps.

Current Behavior

Pickles compiler does not output a pickle for scenarios with no steps.

Possible Solution

I'd love some pointers here. I've never worked on the pickles compiler, but if someone can show me where to start (and we're agreed on the idea), I'd have a go at this.

Context & Motivation

I'm thinking about how people like product owners engage with Cucumber, and that I'd guess they think of a scenario as having taken life as soon as they name it. It seems wrong to hide those scenarios from Cucumber.

TokenScanner is not working on Python 3.11

👓 What did you see?

feature_file = parser.parse(TokenScanner(feature_path))
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.11/site-packages/gherkin/token_scanner.py", line 22, in __init__
  self.io = io.open(path_or_str, 'rU', encoding='utf8')
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid mode: 'rU'

✅ What did you expect to see?

📦 Which tool/library version are you using?

Python 3.11.0
gherkin-official==24.1.0

🔬 How could we reproduce it?

Steps to reproduce the behavior:

  1. Install Python 3.11.0 and gherkin-official==24.1.0
  2. Pass any feature file into TokenScanner
  3. Run
  4. See error ValueError: invalid mode: 'rU'

📚 Any additional context?


This text was originally generated from a template, then edited by hand. You can modify the template here.

Gherkin: Comments after tags not present in GherkinDocument.getCommentsList()

Summary

Comments on the same line as a tag cannot be retrieved from the list of comments.
Applies to tags on both Features and Scenarios.

Example:

# I can find this comment
@myTag #but not this one
Feature: Make comments available through the parser

# comment to be found
@myOtherTag #inaccessible comment
Scenario: If a tag is followed by a comment, the comment should be accessible through the parser.

Expected Behavior

All comments, including the ones following a tag on the same line, should be present in GherkinDocument.getCommentsList().

Current Behavior

Comments after a tag on the same line are inaccessible via the parser.

Context & Motivation

I want to import the complete file contents.
We often use comments after tags to simulate "tags with spaces", so these comments contain valuable information.

Your Environment

  • Version used: io.cucumber.gherkin 17.0.2
  • Operating System and version: Windows 10, JDK 11.0.7 amd64
  • Link to your project: private

java: misleading `StringUtils` method names

🤔 What's the problem you've observed?

The https://github.com/cucumber/gherkin/blob/main/java/src/main/java/io/cucumber/gherkin/StringUtils.java class provides methods to trim text but keeping new lines:

  • StringUtils.ltrimKeepNewLines(String)
  • StringUtils.rtrimKeepNewLines(String)

The method names suggest that all new lines that on the left (respectively on the right) are kept.

These two methods are working well when there is one new line to keep. However, the following unit tests shows an unexpected behavior when the text contains multiple newlines:

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class StringUtilTest {
    private static final String WHITESPACE = "\u00A0 \t";
    private static final String CUCUMBER = "🥒";

    @Test
    void testRtrimKeepNewlines() {
        assertEquals(WHITESPACE + CUCUMBER + "\n", StringUtils.rtrimKeepNewLines(WHITESPACE + CUCUMBER + "\n" + WHITESPACE));
    }

    @Test
    void testRtrimKeepNewlines_multiline() {
        assertEquals("\n" + WHITESPACE + "\n" + WHITESPACE + CUCUMBER + "\n\n",
                StringUtils.rtrimKeepNewLines("\n" + WHITESPACE + "\n" + WHITESPACE + CUCUMBER + WHITESPACE + "\n" + WHITESPACE + "\n"));
        // expected: the two WHITESPACE at the and are removed
        // actual: only one WHITESPACE is removed at the end
    }

    @Test
    void testLtrimKeepNewlines() {
        assertEquals("\n" + CUCUMBER + WHITESPACE, StringUtils.ltrimKeepNewLines(WHITESPACE + "\n" + CUCUMBER + WHITESPACE));
    }

    @Test
    void testLtrimKeepNewlines_multiline() {
        assertEquals("\n\n" + CUCUMBER + WHITESPACE + "\n" + WHITESPACE + "\n",
                StringUtils.ltrimKeepNewLines("\n" + WHITESPACE + "\n" + WHITESPACE + CUCUMBER + WHITESPACE + "\n" + WHITESPACE + "\n"));
        // expected: the two WHITESPACE at the beginning are removed
        // actual: only one WHITESPACE is removed at the beginning
    }

}

Thus, either this is:

  • a bug in the method implementation (unknown impact) or
  • the method name is wrong (it should be ltrimKeepNewLine without plural s, respectively rtrimKeepNewLine). Impact is that the developer may think the method removes all whitespaces, not only when there is one newline.

✨ Do you have a proposal for making it better?

Decide if this is an implementation bug or a misleading method name. Then correct accordingly.

library: Support for unique test names in library

Summary

This is a continuation of a discussion on the Slack channel with @tooky @brasmusson @mattwynne and others.

I've tried to cover as much background as I can given the limitations of markdown. Really this is about trying to arrive at a standard naming convention for Pickles in order for tests from many different test frameworks across the Gherkin ecosystem to be reconciled with their corresponding results.

It's similar, but not quite the same (I think) as some of the previous conversations on linking Gherkin with a test management system.

I've tried to include as much context as I can - and stick to the issue template. Though I'm sure it will read a bit funny. It might be best to look at the "context and motivation" section to understand why I think it would be useful.

Expected Behavior

It would be lovely if all Gherkin test results had a standardised identifier that was easily linkable to the Gherkin that the test result came from without any a priori knowledge of which result belongs to which feature file.

Current Behavior

The issue as I see it is that each test framework uses a different naming convention for each test (pickle) - and the naming conventions that are used are "lossy" - for example, SpecFlow's MSTest doesn't include line number information, SpecFlow's XUnit truncates test names at a certain number of characters (long scenario outline names with quite a lot of columns/long content in the table). Karma-Gherkin-Feature's were so inconsistent we had to fork it because we just couldn't make it work.

In discussion with @brasmussen in the Gherkin Slack space, he suggested using file and line number - which may work (in principle) for automated tests - except the frameworks out there don't include this information in their test output - or at least, don't all include this information.

Possible Solution

I wondered if we could encourage consistency in the tool ecosystem by providing one (or more) standard identifiers for tests from the Gherkin parser.

It wouldn't fix all problems, and it would need uptake from the folks who write the test frameworks, but if it's easier to be consistent than to be inconsistent, we might see improved interoperatiblity between tools in the ecosystem.

One thing to note is that I think there's a marked difference between our automation and manual use cases (see context and motivation below):

  • For the automation use cases, we can assume that the test results are "contemporaneous" with the feature file - that is - if they claim to come from a given feature file, they all come from the same version, so somehow using feature name and line numbers in an identification scheme might work (or even something more unique, like a digest of the whole feature file content and the line number).

  • For the manual use cases, we need to consider the case where we have a feature with (say) 8 scenarios, one of which is manual, and the remaining 7 automated, were we to something like feature name and line number, when anyone changed one of the 7 automated result, it would change the ID of the manual test also - and would invalidate the linkage to the previous result.
    -> In this instance, I wondered if something like a digest of the feature name, and the content (including arguments, data tables etc.) of each pickle would be useful.

  • In either cases, even using manually added unique tags to scenarios wouldn't really help - as most of the test frameworks I've seen don't include the tags in the results anyway - and it would require a herculean work of manual effort to maintain consistency.

Because of the new cross-language support in Gherkin 6, it seems a real opportunity to help improve interoperability across the ecosystem as in time, most test framework implementations would come to rely on the new parser (with whatever test ID scheme it contained).

Context & Motivation

We like ATDD/BDD!

We really like BDD/ATDD.

We are a large organisation (ca. 400 developers/testers)

We have a relatively small number of products, but they are large.

We have a large number (~16000) of Gherkin files describing our products. Most written in the style of tests, but increasingly as proper executable specification.

We have a mixture of tools and technologies - some more historic, some less so.

Many of our automation tests are written in Gherkin. We have a number of tools in use - SpecFlow2.0 (MSTest), SpecFlow3.0 (XUnit), karma-jasmine-feature (maybe to be replaced with cucumber.js).

Are we finished yet?

Sometimes tests don't get run. Sometimes tests get disabled. In some frameworks (like SpecFlow), we get a result that says the test was ignored. In other frameworks, we don't get a result at all.

It's therefore really important for us to use to be able to reconcile the test results with the specification (i.e. the Gherkin) to know we've actually implemented everything we should (and someone hasn't accidentally left a test turned off because it was flickering, or something like).

So we trace to our Gherkin Specifications by tagging the Feature, Scenario, Outline or Example table with the external requirement ID (so we can review which detailed specs address each requirement, and whether we think that's enough)

  • and we reconcile the test results we have with the Gherkin Specification to make sure all the right tests have been run.

Automation

Because we use a mixture of technologies, we also have a mixture of test frameworks (some SpecFlow/MSTest, some karma-gherkin-feature, some SpecFlow/XUnit, some cucumberjs). Each has a different convention for how it names pickles in the results - and all are in some way "lossy".

Our results can be quite fragmented - because our Gherkin is a behavioural specification (and we use them to generate product documentation), when they are written, we pay no mind to how fast or slow a behaviour is to test - only whether we have refined and specified the right behaviour.

This means that for a given feature file, some pickles are run at one (fast) stage of the pipeline, and some at later (e.g. overnight) stages of the pipeline, and at the end, we have to aggregate many different results files together and tie them back to the feature file (see earlier) to make sure we've covered everything.

In many of our pipelines (cloud and deployment environment), the tools don't have reliable access to the original Gherkin at the point the tests are run.

We have similar arrangements with our nightly builds - where tests are run off-line in a deployment environment.

Our cloud pipelines build the test executables, pack them into docker images, spin them out to multiple deployment environments in the cloud, and then post the results back.

Because of the multiplicity of tools involved (and their not-quite-consistent naming conventions), the fact that lots of those tools don't exist in the deployment environments, the fact that many points in out build pipeline don't have access to both the Gherkin and the test results at the same time, this makes reconciling our tests and test results really quite challenging.

Manual

Also - because we really like BDD/ATDD, we don't pay any mind when writing feature files as to whether we will automate a given scenario or whether we will run it manually. Because the feature file is the specificiation - which doesn't really care how we intend to test it.

In these instances, we tag scenarios (or other taggable constructs) "@manualtest", and have a tool which generates a pro-forma PDF form which our manual testers use to complete their results.

Those PDFs are also reconciled against the orginal feature, showing that between the automation and manual test results, we have results covering the whole specification.

Your Environment

  • Version used:
  • Operating System and version:
  • Link to your project:

Separate the dependency between Gherkin and Messages

🤔 What's the problem you're trying to solve?

Currently the Gherkin parser parsers directly into message objects. This means that

  • When messages updates, Gherkin gets an update.
  • When messages updates, projects that dependency on messages transitively through Gherkin gets an update.
  • When a project wants to upgrade Gherkin they have to upgrade Messages
  • When a project wants to upgrade Messages they have to upgrade Gherkin

And because messages gets major releases, Gherkin also gets frequent major releases. This has a lot of bad effects all around.

  • Messages can not be released and upgraded in a Cucumber implementation independently from Gherkin (each release of messages has to be propagated to Gherkin first). This results in busy work for maintainers that is frequently not done.
  • Upgrading either Gherkin or Messages results in quite a bit of mandatory work for down stream maintainers (e.g. cucumber/messages#107 (comment)).
  • And because messages are also used as the interface between different Cucumber implementations and various plugins these now also get Mandatory upgrades (e.g. allure-framework/allure-java@a79c669).

This makes the ecosystem around Cucumber either unreliable or stagnant depending on what release strategy a maintainer favors.

✨ What's your proposed solution?

  1. The Gherkin parser produces an AST that is similair to, but not the equivalent of Message
  2. Cucumber implementations map the AST to a Message
  3. Extend the CCK with the acceptance test examples from Gherkin
  4. Validate the mapping in a Cucumber implemetnation is correct using the CCK.

⛏ Have you considered any alternatives or workarounds?

I could be possible to make changes to Gherkin and Messages less frequently, but given that this is an Opensource project that mostly runs on people spare time such obstacles would likely discourage contribution in the first place.

Better testing approach for the generated parser?

Currently we test the parser primarily via the testdata features. These are pretty good as documentation of the correct behaviour in specific situations.

However looking at 'coverage', they cover less than 30% of the Parser's LOC in the PHP version, and probably similar in others.

Is there another approach we can use to validate the Parser is 'correct' in a wide range of situations? I'm thinking

  • Fuzz testing?
  • Property-based testing?
  • Some sort of approvals-based testing?

php: Parser is not generated with the right formatting

🤔 What's the problem you've observed?

One of the goals of setting up the workflow for this project was that generating parsers should only depend on Berp. This simplifies the image needed to build this project. However PHP also formatted the parser using vendored tools. This effectively adds a dependency on PHP.

gherkin/php/Makefile

Lines 47 to 52 in 6b84ba8

build/classes.php: gherkin-php.razor gherkin.berp
$(berp-generate-parser)
csplit --quiet --prefix=build/Generated --suffix-format=%02d.php.tmp --elide-empty-files build/classes.php /^.*.php$$/ {*}
for file in build/Generated**; do mkdir -p src-generated/$$(head -n 1 $$file | sed 's/[^/]*.php$$//'); done
for file in build/Generated**; do tail -n +2 $$file > src-generated/$$(head -n 1 $$file); rm $$file; done
vendor/bin/php-cs-fixer --diff fix src-generated

✨ Do you have a proposal for making it better?

Either

  • fix gherkin-php.razor to produce correctly formatted files
  • or ignore the problem. It is generated code.

💻 Additional context

In #3 I've removed the code formatter and fixed most of the razor file. I couldn't fix everything.

Split from monorepo notes

Create the contents of this repo using https://github.com/newren/git-filter-repo.

#!/bin/bash
set -ex

git clone [email protected]:cucumber/common.git gherkin
pushd gherkin
git filter-repo --path gherkin/ --path-rename 'gherkin/:' --tag-rename 'gherkin/':''
git tag  | grep --invert-match "^v.*" | xargs git tag -d
git remote add origin [email protected]:cucumber/gherkin.git
git push --force --set-upstream origin main
git push --tags
popd

TODO:

  • Copy repo configuration from messages
  • Test code gen in action
    • c
    • dart
    • dotnet
    • elixir
    • go
    • java
    • javascript
    • objective-c
    • perl
    • php
    • python
    • ruby
  • Setup github actions for
    • c
    • dart
    • dotnet
    • elixir
    • go -- integration tests don't work on windows
    • java -- integration tests don't work on windows
    • javascript -- dropped node 12,14 (module problems, I guess)
    • objective-c
    • perl
    • php
    • python
    • ruby
  • Setup github secrets
  • Clean up mono repo files
    • Makefile
    • default.mk
    • .rsync
    • <language>/bin and <language>/script folders
    • <language>/.github folders
  • Deduplicate or check gherkin-languages.json
  • Update/check READMEs
  • Add RELEASING.md
  • Check and reformat CHANGELOG.md
  • Update references to common repo to gherkin in this project.
  • Make a release
  • Tag with polyglot-release
  • Remove code from common cucumber/common#2122
  • Move issues from common to this repo
  • Archive and redirect gherking-<language> repos on Github.
  • Setup Renovate

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.