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**:
   ```bash
   composer require behat/gherkin

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

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

    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('features/user_login.feature');
    $featureNode = $parser->parse($featureContent);
    
    // Access parsed data (e.g., scenarios, steps)
    foreach ($featureNode->getChildren() as $child) {
        if ($child instanceof \Behat\Gherkin\Node\ScenarioNode) {
            echo "Scenario: " . $child->getTitle() . "\n";
        }
    }
    
  2. Where to Look First:

    • Lexer: Tokenizes Gherkin syntax (e.g., Given, When, Then).
    • Parser: Converts tokens into a structured FeatureNode object.
    • Node Classes: Inspect \Behat\Gherkin\Node (e.g., FeatureNode, ScenarioNode, StepNode) for parsed data structure.
    • Keywords: Customize language support via ArrayKeywords or DialectProviderInterface (v4.15+).

Implementation Patterns

1. Parsing Feature Files

  • Workflow:

    1. Load feature file content (e.g., from storage/app/features/ or resources/features/).
    2. Initialize Lexer with language keywords (default: English).
    3. Parse content into a FeatureNode:
      $parser = new Parser(new Lexer($keywords));
      $featureNode = $parser->parse(file_get_contents($path));
      
    4. Traverse the node tree:
      $scenarios = $featureNode->getChildrenOfType(\Behat\Gherkin\Node\ScenarioNode::class);
      foreach ($scenarios as $scenario) {
          $steps = $scenario->getSteps();
          foreach ($steps as $step) {
              $text = $step->getText(); // e.g., "Click the login button"
              $keyword = $step->getKeyword(); // e.g., "Given"
          }
      }
      
  • Integration with Laravel:

    • Store parsed features in the cache for performance:
      $cacheKey = 'gherkin.feature.' . md5($path);
      $featureNode = Cache::remember($cacheKey, now()->addHours(1), function () use ($parser, $path) {
          return $parser->parse(file_get_contents($path));
      });
      
    • Use in Laravel commands or controllers to validate/test business logic.

2. Customizing Language Keywords

  • Default Keywords:

    $keywords = new ArrayKeywords([
        'en' => [
            'feature' => 'Feature',
            'given' => 'Given',
            // ... other keywords
        ],
        'es' => [
            'feature' => 'Característica',
            'given' => 'Dado',
        ]
    ]);
    
  • Dynamic Language Selection:

    $language = request()->header('Accept-Language') ?? 'en';
    $keywords = new ArrayKeywords([$language => [...]]);
    
  • DialectProviderInterface (v4.15+): For advanced use cases, implement DialectProviderInterface to load keywords dynamically:

    use Behat\Gherkin\Dialect\DialectProviderInterface;
    
    class CustomDialectProvider implements DialectProviderInterface {
        public function getDialect(string $language): array {
            return [
                'Feature' => 'CustomFeature',
                'Given' => 'CustomGiven',
            ];
        }
    }
    

3. Handling Step Definitions

  • Extract Step Text:

    $stepText = $stepNode->getFullText(); // Includes keyword (e.g., "Given I am on the homepage")
    $stepText = $stepNode->getText();     // Only the step text (e.g., "I am on the homepage")
    
  • Table/Argument Parsing:

    if ($stepNode->hasArgument()) {
        $argument = $stepNode->getArgument();
        if ($argument instanceof \Behat\Gherkin\Node\TableNode) {
            $rows = $argument->getRows();
            foreach ($rows as $row) {
                $cells = $row->getCells();
            }
        }
    }
    
  • Example Scenarios:

    $examples = $scenarioOutline->getExamples();
    foreach ($examples as $example) {
        $table = $example->getTable();
        $rows = $table->getRows();
    }
    

4. Validation and Error Handling

  • Catch Parser Exceptions:
    try {
        $featureNode = $parser->parse($content);
    } catch (\Behat\Gherkin\Exception\ParserException $e) {
        Log::error("Gherkin parse error: " . $e->getMessage());
        throw new \RuntimeException("Invalid feature file syntax", 0, $e);
    }
    
  • Check for Deprecated Syntax: Use GherkinCompatibilityMode (v4.15+) to enforce strict parsing:
    $parser = new Parser($lexer, new \Behat\Gherkin\GherkinCompatibilityMode('gherkin-32'));
    

5. Performance Optimization

  • Caching Parsed Features:
    $cache = new \Behat\Gherkin\Loader\FileLoader(
        new \Behat\Gherkin\Loader\CachingLoader(
            new \Behat\Gherkin\Loader\FileLoader(new \Behat\Gherkin\Lexer($keywords)),
            new \Symfony\Component\Cache\Adapter\FilesystemAdapter()
        )
    );
    $featureNode = $cache->load($path);
    
  • Lazy Loading: Parse features only when needed (e.g., in a service provider):
    $this->app->singleton('feature.parser', function () {
        return new Parser(new Lexer(new ArrayKeywords(['en' => [...]))));
    });
    

Gotchas and Tips

Pitfalls

  1. Language Mismatches:

    • If the feature file specifies an unsupported language (e.g., # language: xyz), the parser will fall back to English (v4.15+). To enforce strict parsing:
      $parser = new Parser($lexer, null, true); // $strictLanguage = true
      
    • Fix: Validate language tags in CI using tools like gherkin-lint.
  2. Deprecated Syntax:

    • Tag filters without @ (e.g., wip&&~slow) are deprecated (v4.16.1). Use @wip&&~@slow instead.
    • Fix: Update feature files or use GherkinCompatibilityMode::LEGACY temporarily.
  3. Background Placement:

    • A Background section after the first Scenario will throw a ParserException (v4.14+).
    • Fix: Reorder sections in the feature file.
  4. Empty Feature Files:

    • Files without a Feature: keyword will trigger a ParserException (v4.14+).
    • Fix: Ensure all .feature files start with Feature:.
  5. Table Parsing Quirks:

    • Trailing content after | in tables is ignored (v4.14+), but malformed tables may still cause issues.
    • Fix: Use tools like gherkin-lint to validate syntax.

Debugging Tips

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

    $lexer = new Lexer($keywords);
    $tokens = $lexer->tokenize(file_get_contents('feature.feature'));
    print_r($tokens);
    
  2. Node Structure: Dump the parsed FeatureNode to understand its structure:

    use Symfony\Component\VarDumper\Cloner\VarCloner;
    (new VarCloner())->dump($featureNode);
    
  3. **

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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope