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

Behat Spec Laravel Package

rmiller/behat-spec

Behat extension that integrates with PhpSpec to prevent fatal errors on missing classes or methods. Automatically generates specs and examples when Behat encounters undefined domain objects, then can run phpspec to create the code.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel + Behat + PhpSpec

  1. Install the package in your Laravel project (dev dependency):

    composer require --dev rmiller/behat-spec:^0.5
    
  2. Configure Behat (behat.yml):

    extensions:
        RMiller\BehatSpec\Extension\BehatSpecExtension\BehatExtension:
            path: vendor/bin/phpspec  # Laravel's vendor/bin path
            config: path/to/phpspec.yml  # Optional: Custom PhpSpec config
    
  3. Configure PhpSpec (phpspec.yml):

    extensions:
        RMiller\BehatSpec\Extension\BehatSpecExtension\PhpSpecExtension: ~
    
  4. First Use Case:

    • Write a Behat feature referencing a non-existent class/method (e.g., Product::namedAndPriced()).
    • Run the feature:
      vendor/bin/behat
      
    • When Behat encounters the missing class/method, the package will:
      • Prompt to generate a PhpSpec for the class.
      • Add method examples to the spec.
      • Optionally create the class stub via phpspec run.

Implementation Patterns

Workflow: Domain Modeling with Behat + PhpSpec

  1. Define a Feature:

    Feature: Product Catalog
      Scenario: Add a product
        Given a product named "Laptop" and priced £999 was added to the catalogue
    
    • Context method (missing class/method):
      public function aProductNamedAndPricedWasAddedToTheCatalogue($name, $price) {
          $product = Product::namedAndPriced($name, $price); // ❌ Missing class/method
          $this->catalogue->add($product);
      }
      
  2. Run Behat:

    • The package intercepts the error, prompts to generate a spec:
      [BehatSpec] Product class not found. Generate spec? (y/N) y
      
    • Spec is created (spec/ProductSpec.php):
      namespace spec;
      
      use PhpSpec\ObjectBehavior;
      use Product;
      
      class ProductSpec extends ObjectBehavior
      {
          public function it_is_initializable()
          {
              $this->shouldHaveType(Product::class);
          }
      
          public function it_has_a_namedAndPriced_method($name, $price)
          {
              $this->namedAndPriced($name, $price)->shouldReturnAnInstanceOf(Product::class);
          }
      }
      
  3. Auto-Generate the Class:

    • The package prompts to run phpspec run:
      [BehatSpec] Run phpspec run to create Product? (y/N) y
      
    • Class stub is generated (src/Product.php):
      namespace App;
      
      class Product
      {
          public static function namedAndPriced($name, $price)
          {
              // TODO: Implement method
          }
      }
      
  4. Iterate:

    • Re-run Behat. The package now adds examples for missing methods (e.g., namedAndPriced).
    • Implement the method in Product.php and re-run specs:
      vendor/bin/phpspec run
      

Integration Tips for Laravel

  1. Laravel Service Container:

    • If using Behat contexts as service providers, bind generated classes to the container:
      // In a Behat service provider
      $this->app->bind(Product::class, function () {
          return new Product();
      });
      
  2. Eloquent Models:

    • For auto-generated Eloquent models, extend the PhpSpec config to use Laravel’s make:model:
      # phpspec.yml
      rerunner:
          commands: [describe, exemplify, "php artisan make:model"]
      
  3. CI/CD Automation:

    • Avoid interactive prompts in pipelines by scripting the workflow:
      # Example: Non-interactive Behat + PhpSpec run
      vendor/bin/behat --no-interaction && \
      vendor/bin/phpspec run --no-interaction
      
  4. Custom Paths:

    • Point to Laravel’s vendor/bin paths:
      # behat.yml
      extensions:
          RMiller\BehatSpec\Extension\BehatSpecExtension\BehatExtension:
              path: vendor/bin/phpspec
      
  5. PhpSpec Configuration:

    • Use Laravel’s app_path() for spec/config paths:
      # phpspec.yml
      rerunner:
          config: app_path('phpspec.yml')
      

Gotchas and Tips

Pitfalls

  1. Interactive Prompts in CI:

    • The package blocks execution for user input (e.g., "Generate spec?"). Solution:
      • Use --non-interactive flags or script responses:
        echo "y" | vendor/bin/behat
        
      • Or fork the package to remove prompts.
  2. PHP 8.x Compatibility:

    • The package was last updated for PHP 5.6. Issues may arise with:
      • Typed properties (e.g., Product::namedAndPriced(string $name, float $price)).
      • Strict typing in PhpSpec 5.x.
    • Workaround: Pin dependencies to PhpSpec 3.x in composer.json:
      "require-dev": {
          "phpspec/phpspec": "3.6",
          "behat/behat": "3.8"
      }
      
  3. Class Overwriting:

    • If phpspec run generates a class that conflicts with existing Laravel classes (e.g., User), the package won’t detect it. Solution:
      • Exclude directories in phpspec.yml:
        suites:
            app:
                namespace: App
                psr4_prefix: App
                exclude:
                    - "App/Models/User"  # Skip existing models
        
  4. Namespace Conflicts:

    • Generated specs/classes may use incorrect namespaces if Laravel’s autoloader isn’t configured. Fix:
      • Ensure phpspec.yml matches Laravel’s composer.json autoload paths:
        # phpspec.yml
        suites:
            app:
                namespace: App
                psr4_prefix: App
        
  5. Laravel Artisan Conflicts:

    • If using phpspec run to generate Eloquent models, conflicts may arise with Laravel’s migrations. Tip:
      • Generate models after migrations or use a custom command:
        php artisan make:model Product --spec
        

Debugging Tips

  1. Verbose Logging:

    • Enable debug mode in behat.yml:
      default:
          extensions:
              RMiller\BehatSpec\Extension\BehatSpecExtension\BehatExtension:
                  debug: true
      
  2. Manual Spec Generation:

    • If the package fails, manually generate specs:
      vendor/bin/phpspec describe App/Product
      
  3. Check PhpSpec Run Commands:

    • Verify phpspec run works standalone:
      vendor/bin/phpspec run --no-interaction
      
  4. Forking the Package:

    • To add Laravel support (e.g., Eloquent integration), fork and modify:
      • RMiller\BehatSpec\Extension\BehatSpecExtension\PhpSpecExtension.
      • Add a laravel config option to phpspec.yml.

Extension Points

  1. Custom Commands:

    • Override phpspec run commands in phpspec.yml:
      rerunner:
          commands: [describe, exemplify, "php artisan make:model"]
      
  2. Pre/Post-Hooks:

    • Extend the package by listening to Behat events (e.g., BeforeScenario):
      // In a Behat service provider
      $this->getServiceContainer()->set('behat_spec_hook', function () {
          return new class {
              public function beforeScenario(BeforeScenarioEvent $event) {
                  // Custom logic before BehatSpec runs
              }
          };
      });
      
  3. Non-Interactive Mode:

    • Disable prompts by monkey-patching the package’s ConsoleIO class:
      // In a Behat extension
      $this->getServiceContainer()->set('behat_spec.console_io', function () {
          return new class extends \Symfony\Component\Console\ConsoleIO {
              public function ask($question, $default = null) {
                  return $default; // Auto-answer
      
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor