Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Gherkin Laravel Package

behat/gherkin

behat/gherkin is a PHP library for parsing the Gherkin language used in BDD. Read and tokenize feature files, build an AST, and integrate with Behat or other test runners to execute human-readable scenarios in your test suite.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require behat/gherkin
    

    Add to composer.json if using Laravel's autoloader:

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Behat\\Gherkin\\": "vendor/behat/gherkin/src/"
        }
    }
    
  2. First Use Case: Parse a .feature file in a Laravel command or controller:

    use Behat\Gherkin\Parser;
    use Behat\Gherkin\Lexer;
    use Behat\Gherkin\Keywords\ArrayKeywords;
    
    $keywords = new ArrayKeywords(['en' => [...]]); // Default English keywords
    $lexer = new Lexer($keywords);
    $parser = new Parser($lexer);
    
    $featureContent = file_get_contents(storage_path('features/auth.feature'));
    $featureNode = $parser->parse($featureContent);
    
    // Access parsed data
    $featureTitle = $featureNode->getTitle();
    $scenarios = $featureNode->getChildren();
    
  3. Where to Look First:

    • Lexer: Tokenizes Gherkin syntax (e.g., Given, When, Then).
    • Parser: Converts tokens into a structured FeatureNode object.
    • Node Classes: FeatureNode, ScenarioNode, StepNode, TableNode, etc. (see src/Node/).
    • Keywords: Customize language support via ArrayKeywords or DialectProviderInterface (v4.15+).

Implementation Patterns

1. Parsing Feature Files

  • Workflow:

    1. Load feature content (file, string, or stream).
    2. Initialize Lexer with language keywords.
    3. Parse using Parser to get a FeatureNode.
    4. Traverse the node tree to extract scenarios, steps, tables, etc.
  • Example: Extract Scenarios

    $scenarios = $featureNode->getChildren();
    foreach ($scenarios as $scenario) {
        $steps = $scenario->getSteps();
        foreach ($steps as $step) {
            $keyword = $step->getKeyword();
            $text = $step->getText();
            // Log or process step: e.g., dispatch to Laravel events
        }
    }
    

2. Custom Keywords/Dialects

  • Extend ArrayKeywords for simple customizations:
    $customKeywords = new ArrayKeywords([
        'en' => [
            'feature' => 'Use Case',
            'given' => 'Setup',
            'when' => 'Action',
            'then' => 'Outcome',
        ]
    ]);
    $lexer = new Lexer($customKeywords);
    
  • Use DialectProviderInterface (v4.15+) for advanced dialects:
    use Behat\Gherkin\Dialect\DialectProviderInterface;
    class CustomDialect implements DialectProviderInterface {
        public function getDialect(string $language): array {
            return [
                'Given' => 'Setup',
                'When' => 'Action',
                // ...
            ];
        }
    }
    

3. Integration with Laravel

  • Service Provider: Bind the parser as a singleton in AppServiceProvider:
    $this->app->singleton(Parser::class, function ($app) {
        $lexer = new Lexer(new ArrayKeywords(['en' => []]));
        return new Parser($lexer);
    });
    
  • Artisan Command: Parse features on demand:
    use Illuminate\Console\Command;
    use Behat\Gherkin\Parser;
    
    class ParseFeaturesCommand extends Command {
        protected $signature = 'features:parse {file}';
        public function handle(Parser $parser) {
            $feature = $parser->parse(file_get_contents($this->argument('file')));
            $this->info($feature->getTitle());
        }
    }
    
  • Event Dispatching: Trigger Laravel events for parsed steps:
    event(new StepExecuted($step->getKeyword(), $step->getText()));
    

4. Handling Tables and Data

  • Extract Tables:
    $tables = $scenario->getTableNodes();
    foreach ($tables as $table) {
        $rows = $table->getRows();
        $headers = $table->getHeader();
        // Convert to Laravel collections or arrays
        $data = collect($rows)->map(fn($row) => array_combine($headers, $row));
    }
    
  • Use with Laravel Eloquent:
    $users = User::whereIn('name', $data->pluck('name')->all())->get();
    

5. Caching Parsed Features

  • Cache the FeatureNode:
    $cacheKey = 'features.auth';
    $feature = Cache::remember($cacheKey, now()->addHours(1), function () use ($parser) {
        return $parser->parse(file_get_contents(storage_path('features/auth.feature')));
    });
    

6. Validation and Error Handling

  • Catch Parser Exceptions:
    try {
        $feature = $parser->parse($content);
    } catch (\Behat\Gherkin\Exception\ParserException $e) {
        report($e); // Laravel's error reporting
        throw new \RuntimeException('Invalid Gherkin syntax', 0, $e);
    }
    
  • Validate Syntax: Use gherkin-lint in CI or validate tags/steps programmatically:
    $invalidTags = $featureNode->getTags()->filter(fn($tag) => !str_starts_with($tag, '@'));
    

Gotchas and Tips

Pitfalls

  1. Deprecated Syntax:

    • Avoid tag filters without @ (e.g., wip&&~slow). Use @wip&&~@slow (v4.16.1+).
    • Extending Lexer/Parser directly is deprecated. Use ParserInterface (v4.15+).
  2. Language Handling:

    • Invalid language tags (e.g., #language:no-such) now throw exceptions in gherkin-32 mode (default: falls back to en).
    • Whitespace in language tags (e.g., #language: en) is allowed in gherkin-32 mode.
  3. Step Keywords:

    • Step keywords (e.g., Given, When) are trimmed by default. Use gherkin-32 mode to preserve whitespace.
  4. Table Parsing:

    • Content after | in tables is ignored (not an error in v4.14+).
    • Unicode padding in tables is trimmed (v4.16.0+).
  5. Performance:

    • Parsing large feature files can hit PHP’s recursion limit. Use gherkin-32 mode for deeper compatibility with Cucumber.
  6. Backward Compatibility:

    • Scenario and Scenario Outline are treated as synonyms (v4.14+). Use Examples to distinguish.

Debugging Tips

  1. Inspect Tokens: Use the Lexer to debug tokenization:

    $lexer = new Lexer(new ArrayKeywords(['en' => []]));
    $tokens = $lexer->tokenize(file_get_contents('feature.feature'));
    dd($tokens); // Inspect raw tokens
    
  2. Enable gherkin-32 Mode: For stricter Cucumber parity:

    $parser = new Parser($lexer, new \Behat\Gherkin\GherkinCompatibilityMode('gherkin-32'));
    
  3. Check Node Structure: Dump the FeatureNode to understand its hierarchy:

    dd($featureNode->toArray()); // Recursive array representation
    
  4. Handle Comments: Comments are parsed but not exposed in the node tree. Use getComments() on nodes if needed (v4.7.3+).

Extension Points

  1. Custom Node Types: Extend Node\Node or implement NodeInterface for domain-specific nodes.

  2. Pre/Post-Processing: Wrap the parser to add metadata or transform nodes:

    class FeatureProcessor {
        public function process(FeatureNode $feature) {
            $feature->setMetadata(['parsed_at' => now()]);
            return $feature;
        }
    }
    
  3. Loader Integration: Use Loader\LoaderInterface to load from non-file sources (e.g., database):

    $loader = new \Behat\Gherkin\Loader\FileLoader();
    $feature = $loader->load(storage_path('features/auth.feature'));
    
  4. Tag Filtering: Implement custom tag logic:

    $tags
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata