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 Symfony Extension Laravel Package

bytes-commerce/behat-symfony-extension

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the package**:
   ```bash
   composer require bytes-commerce/behat-symfony-extension
  1. Configure Behat (behat.yml):
    extensions:
        BytesCommerce\Behat\SymfonyExtension:
            kernel:
                path: "%paths.base%/config/kernel.php"  # Path to your Symfony kernel
            mink:
                sessions:
                    default:
                        symfony: ~
    
  2. Define a Symfony service context (src/Context/FeatureContext.php):
    namespace App\Context;
    
    use Behat\Behat\Context\Context;
    use Symfony\Component\HttpKernel\KernelInterface;
    
    final class FeatureContext implements Context
    {
        public function __construct(private KernelInterface $kernel) {}
    
        /**
         * @Given I access the homepage
         */
        public function iAccessTheHomepage(): void
        {
            $response = $this->kernel->getContainer()->get('router')->generate('homepage');
            // Assertions or further logic
        }
    }
    
  3. Register the context as a service (config/services.yaml):
    services:
        App\Context\FeatureContext:
            tags: ['behat.context']
    
  4. Run Behat:
    ./vendor/bin/behat
    

First Use Case

Test a Symfony route without spinning up a server:

Feature: Homepage
  Scenario: Load homepage
    Given I access the homepage
    Then the response status code should be 200

Implementation Patterns

Context as a Service

  • Autowiring: Define contexts as Symfony services with type-hinted dependencies (e.g., KernelInterface, EntityManagerInterface).
    use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
    
    #[Autoconfigure]
    class UserContext implements Context {
        public function __construct(private UserRepository $userRepo) {}
    }
    
  • Tagging: Use the behat.context tag to auto-discover contexts.
    services:
        App\Context\UserContext:
            tags: ['behat.context']
    

Mink Integration

  • SymfonyDriver: Test UI interactions without a server:
    mink:
        sessions:
            default:
                symfony: ~
    
  • Page Objects: Integrate with FriendsOfBehat/PageObjectExtension:
    use FriendsOfBehat\PageObjectExtension\Page\Page;
    
    class LoginPage extends Page {
        public function submitLogin(): void { /* ... */ }
    }
    
    Register the page in a context:
    use FriendsOfBehat\PageObjectExtension\Page\CrawlerAwarePageInterface;
    
    class LoginContext implements Context, CrawlerAwarePageInterface {
        public function getPage(): LoginPage { /* ... */ }
    }
    

BrowserKit for Headless Testing

  • Lightweight Testing: Use BrowserKitDriver for non-UI tests:
    mink:
        sessions:
            browserkit:
                browserkit: ~
    
    Access the container in contexts:
    use Symfony\Component\HttpFoundation\Request;
    
    class ApiContext implements Context {
        public function __construct(private RequestStack $requestStack) {}
    
        public function iSendARequest(): void {
            $request = $this->requestStack->getCurrentRequest();
            // Assertions...
        }
    }
    

Workflows

  1. Feature-Driven Development:

    • Write Gherkin scenarios first, then implement contexts as services.
    • Example: Test a form submission with Mink:
      Scenario: Submit a contact form
        Given I am on the contact page
        When I fill the form with:
          | name   | email          |
          | John   | john@example.com |
        And I press "Submit"
        Then I should see "Thank you!"
      
    • Context:
      class ContactContext implements Context {
          public function __construct(private ContactFormHandler $formHandler) {}
      
          public function iFillTheForm(array $data): void {
              $this->formHandler->submit($data);
          }
      }
      
  2. Dependency Injection:

    • Pass services to contexts via constructor injection.
    • Example: Test a Doctrine repository:
      class UserContext implements Context {
          public function __construct(private UserRepository $repo) {}
      
          public function iCreateAUser(): void {
              $this->repo->save(new User());
          }
      }
      
  3. Shared State:

    • Use BeforeScenario/AfterScenario hooks to manage test state:
      use Behat\Behat\Hook\Scope\ScenarioScope;
      
      class HookContext implements Context {
          public function beforeScenario(ScenarioScope $scope): void {
              $container = $scope->getEnvironment()->getKernel()->getContainer();
              $container->get('doctrine')->getConnection()->beginTransaction();
          }
      
          public function afterScenario(ScenarioScope $scope): void {
              $container = $scope->getEnvironment()->getKernel()->getContainer();
              $container->get('doctrine')->getConnection()->rollBack();
          }
      }
      

Gotchas and Tips

Pitfalls

  1. Kernel Path Configuration:

    • Ensure kernel.path in behat.yml points to your Symfony kernel file (e.g., config/kernel.php).
    • Error: No kernel found → Verify the path and file existence.
  2. Mink Session Defaults:

    • If using symfony: driver, ensure BrowserKitDriver is installed (auto-checked by the extension).
    • Fix: Install via Composer:
      composer require --dev friends-of-behat/mink-browserkit-driver
      
  3. Context Initialization:

    • Contexts tagged as behat.context must be public and instantiable by Symfony’s DI container.
    • Error: Context "App\Context\PrivateContext" is not instantiable → Make the class public and constructor public.
  4. Circular Dependencies:

    • Avoid circular references between contexts (e.g., ContextA → ContextB → ContextA).
    • Workaround: Use service IDs or lazy-loading via getService().
  5. Symfony 5+ Cache:

    • Clear the Symfony cache before running Behat to avoid stale services:
      php bin/console cache:clear
      

Debugging Tips

  1. Enable Debug Mode:

    • Set debug: true in behat.yml to see detailed error traces:
      extensions:
          BytesCommerce\Behat\SymfonyExtension:
              debug: true
      
  2. Inspect the Kernel:

    • Access the kernel in a context to debug:
      public function __construct(KernelInterface $kernel) {
          if (!$kernel->isDebug()) {
              throw new \RuntimeException('Kernel must be in debug mode!');
          }
      }
      
  3. Mink Session Dumps:

    • Use dump() in Mink contexts to inspect the DOM:
      use FriendsOfBehat\MinkExtension\Context\MinkContext;
      
      class MyMinkContext extends MinkContext {
          public function someStep(): void {
              $this->getSession()->dump();
          }
      }
      
  4. Service Container Access:

    • Access the container directly in contexts:
      public function __construct(KernelInterface $kernel) {
          $container = $kernel->getContainer();
          $logger = $container->get('logger');
          $logger->info('Test started');
      }
      

Configuration Quirks

  1. Overriding Mink Parameters:

    • Customize Mink parameters via mink_parameters in behat.yml:
      extensions:
          BytesCommerce\Behat\SymfonyExtension:
              mink_parameters:
                  base_url: 'http://localhost:8000'
      
  2. Multiple Sessions:

    • Define multiple Mink sessions (e.g., for parallel testing):
      mink:
          sessions:
              default:
                  symfony: ~
              admin:
                  symfony: ~
      
    • Switch sessions in contexts:
      $this->getSession('admin')->visit($this->locatePath('/admin'));
      
  3. Environment-Specific Config:

    • Use Symfony’s parameter bag to switch configs:
      # config/packages/behat.yaml
      behat:
          kernel_path: '%kernel.project_dir%/config/kernel.php'
      

Extension Points

  1. Custom Context Initializers:
    • Implement ContextInitializer to modify contexts before execution:
      use BytesCommerce\Behat\SymfonyExtension\Context\ContextInitializerInterface;
      
      class DebugInitializer implements ContextInitializerInterface {
          public function initialize(object $context): void {
              if ($context instanceof FeatureContext) {
                  $context->setDebugMode(true);
              }
          }
      }
      
    • Register in behat.yml:
      extensions:
          BytesCommerce\Behat\SymfonyExtension:
      
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.
terminal42/code-quality-tools
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