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

Browser Kit Laravel Package

symfony/browser-kit

Symfony BrowserKit simulates a web browser in PHP for testing and automation: make requests, follow links, click buttons, and submit forms programmatically. Includes an implementation powered by Symfony HttpClient for real HTTP requests.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Install the Package:

    composer require symfony/browser-kit
    

    (No publisher needed; it’s a standalone component.)

  2. First Use Case: Basic Request Simulation

    use Symfony\Component\BrowserKit\HttpBrowser;
    use Symfony\Component\HttpClient\HttpClient;
    
    // Create a browser instance
    $client = HttpClient::create();
    $browser = new HttpBrowser($client);
    
    // Simulate a GET request
    $response = $browser->request('GET', 'https://example.com');
    $content = $response->getContent();
    
    // Extract data (e.g., title)
    $crawler = $browser->getCrawler();
    $title = $crawler->filter('title')->text();
    
  3. Key Starting Points:

    • Official Docs (Laravel-specific examples below).
    • Laravel Integration: Use HttpClient (Symfony’s client, bundled with Laravel) for consistency.
    • Testing: Pair with PHPUnit for assertions (e.g., assertStringContainsString).

First Laravel-Specific Workflow: Testing a Login Flow

use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\DomCrawler\Crawler;

public function testLoginFlow()
{
    $client = HttpClient::create();
    $browser = new HttpBrowser($client);

    // 1. Navigate to login page
    $browser->request('GET', route('login'));
    $crawler = $browser->getCrawler();

    // 2. Fill and submit the form
    $form = $crawler->selectButton('Login')->form([
        'email' => 'user@example.com',
        'password' => 'securepassword',
    ]);
    $browser->submit($form);

    // 3. Assert success (e.g., redirect or welcome message)
    $this->assertStringContainsString('Welcome', $browser->getCrawler()->html());
}

Implementation Patterns

1. Workflow: Automated Form Submission

// Handle multi-step forms (e.g., checkout)
$browser->request('GET', route('checkout.step1'));

// Fill and submit step 1
$form = $browser->getCrawler()->selectButton('Continue')->form([
    'shipping_address' => '123 Main St',
]);
$browser->submit($form);

// Proceed to step 2
$browser->request('GET', $browser->getHistory()->current()->getUri());
$form = $browser->getCrawler()->selectButton('Place Order')->form([
    'payment_method' => 'credit_card',
]);
$browser->submit($form);

2. Workflow: Data Scraping (Laravel + BrowserKit)

use Symfony\Component\BrowserKit\AbstractBrowser;
use Illuminate\Support\Facades\Http;

public function scrapeProductData()
{
    $client = HttpClient::create();
    $browser = new AbstractBrowser($client);

    $browser->request('GET', 'https://store.example.com/products');

    $crawler = $browser->getCrawler();
    $products = [];

    foreach ($crawler->filter('.product-card') as $card) {
        $products[] = [
            'name' => $crawler->filter('.product-name', $card)->text(),
            'price' => $crawler->filter('.price', $card)->text(),
        ];
    }

    // Store in DB or queue for processing
    Product::insert($products);
}

3. Workflow: CI/CD Pre-Deploy Validation

// In a Laravel Artisan command or CI script
public function runPreDeployTests()
{
    $browser = new HttpBrowser(HttpClient::create());

    // Test critical paths
    $this->testLoginFlow($browser);
    $this->testCheckoutFlow($browser);
    $this->testPaymentProcessing($browser);

    if ($browser->getHistory()->hasError()) {
        throw new \RuntimeException('Pre-deploy validation failed!');
    }
}

4. Integration Tips

  • Laravel HTTP Client: Use HttpClient::create() for consistency with Laravel’s ecosystem.
  • DomCrawler: Leverage Symfony’s DomCrawler for CSS selectors and XPath queries.
  • Cookies/Sessions: BrowserKit maintains state across requests:
    $browser->getCookieJar()->set('user_token', 'abc123');
    
  • File Uploads: Handle file inputs in forms:
    $form = $crawler->selectButton('Upload')->form([
        'file' => new \Symfony\Component\HttpFoundation\File\UploadedFile(
            __DIR__.'/test.pdf',
            'test.pdf',
            'application/pdf'
        ),
    ]);
    $browser->submit($form);
    
  • JavaScript Limitation: For JS-heavy apps, combine with Symfony Panther (headless Chrome) or Laravel Dusk (if migrating).

5. Laravel Testing Integration

// In a PHPUnit test case
use Symfony\Component\BrowserKit\HttpBrowser;
use Tests\TestCase;

class LoginTest extends TestCase
{
    public function testLogin()
    {
        $browser = new HttpBrowser(HttpClient::create());
        $browser->request('GET', route('login'));

        $this->assertEquals(200, $browser->getResponse()->getStatusCode());
        $this->assertSelectorTextContains('h1', 'Login');
    }
}

Gotchas and Tips

Pitfalls

  1. No JavaScript Execution:

    • BrowserKit does not render JavaScript. For SPAs or dynamic content, use Symfony Panther or Laravel Dusk.
    • Workaround: Pre-render pages server-side (e.g., with Laravel Mix/Vite) or use a hybrid approach.
  2. Cookie Handling Quirks:

    • Expiration dates must be integers (not strings or DateTime objects) in newer versions (v7.4.3+).
    • Fix: Use time() or strtotime() for timestamps:
      $cookie = new \Symfony\Component\HttpFoundation\Cookie(
          'user_token',
          'abc123',
          time() + 3600 // Integer expiration
      );
      $browser->getCookieJar()->set($cookie);
      
  3. History Tracking:

    • The History object may misinterpret URLs with query parameters without slashes (e.g., ?id=123 vs. /path?id=123).
    • Fix: Normalize URLs before assertions:
      $this->assertStringContainsString('/checkout', $browser->getHistory()->current()->getUri());
      
  4. File Uploads:

    • Empty file fields (<input type="file">) may fail silently. Ensure files are provided even if optional:
      $form['file'] = new \Symfony\Component\HttpFoundation\File\UploadedFile(
          __DIR__.'/empty.txt',
          'empty.txt',
          'text/plain',
          0, // Size
          null,
          true  // Overwrite
      );
      
  5. Response Wrapping:

    • When fetching fragments (e.g., AJAX responses), wrap content for context:
      $response = $browser->getResponse();
      $wrapped = $response->getContent();
      $this->assertStringContainsString('Expected text', $wrapped);
      

Debugging Tips

  1. Inspect Responses:

    $response = $browser->getResponse();
    dump($response->getStatusCode(), $response->getHeaders(), $response->getContent());
    
  2. Enable Verbose Logging:

    $client = HttpClient::create([
        'headers' => ['User-Agent' => 'Laravel BrowserKit Test'],
        'debug' => true, // Enable debug mode
    ]);
    
  3. Check History:

    foreach ($browser->getHistory() as $i => $request) {
        echo "Request {$i}: {$request->getMethod()} {$request->getUri()}\n";
        echo "Response: {$request->getResponse()->getStatusCode()}\n";
    }
    
  4. Use DomCrawler for Selectors:

    • Validate selectors before assertions:
      $crawler = $browser->getCrawler();
      $this->assertCount(1, $crawler->filter('#login-button'));
      

Extension Points

  1. Custom Browser Middleware:

    use Symfony\Component\BrowserKit\AbstractBrowser;
    use Symfony\Component\HttpClient\HttpClientInterface;
    
    class CustomBrowser extends AbstractBrowser
    {
        public function __construct(HttpClientInterface $client)
        {
            parent::__construct($client);
            $this->getCookieJar()->set('custom_token', 'xyz789');
        }
    }
    
  2. Override Request Handling:

    • Extend AbstractBrowser to modify requests (e.g., add headers):
      protected function createRequest($method,
      
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.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
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