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 functional tests: make requests, follow links, fill and submit forms, and inspect responses. Includes an HttpClient-based implementation to perform real HTTP requests programmatically.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

Install via Composer:

composer require symfony/browser-kit

First Use Case: Testing a Form Submission

use Symfony\Component\BrowserKit\HttpFoundation\Session;
use Symfony\Component\BrowserKit\History;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\HttpClient\CurlHttpClient;

// In a PHPUnit test
public function testLoginForm()
{
    $client = new Client(new CurlHttpClient());
    $client->request('GET', '/login'); // Simulate visiting the login page

    $crawler = $client->getCrawler();
    $form = $crawler->selectButton('Login')->form([
        'email' => 'user@example.com',
        'password' => 'secret',
    ]);

    $client->submit($form); // Submit the form
    $this->assertSame(200, $client->getResponse()->getStatusCode());
    $this->assertSelectorTextContains('h1', 'Dashboard');
}

Key Starting Points:

  1. Documentation: Symfony BrowserKit Docs
  2. Core Classes:
    • Client: Simulates a browser (uses HttpClient under the hood).
    • History: Tracks navigation (e.g., ->getCurrentRequest()).
    • DomCrawler: Parses HTML responses (integrates with symfony/css-selector).
  3. Laravel Integration:
    • Use HttpClient (Laravel’s Http facade) as the underlying client for consistency.
    • Combine with Laravel’s Testing\TestCase for database transactions and auth.

Implementation Patterns

1. Workflow: Testing User Flows

Pattern: Chain requests like a user journey.

public function testCheckoutFlow()
{
    $client = new Client(new CurlHttpClient());

    // Step 1: Add to cart
    $client->request('POST', '/cart/add', [
        'product_id' => 123,
        '_token'     => csrf_token(),
    ]);

    // Step 2: Navigate to cart
    $client->clickLink('View Cart');

    // Step 3: Proceed to checkout
    $form = $client->getCrawler()->selectButton('Checkout')->form();
    $client->submit($form);

    // Assert final state
    $this->assertSame('/order/confirmation', $client->getHistory()->current()->getUri());
}

2. Integration with Laravel Testing

Pattern: Extend Laravel’s TestCase to reuse BrowserKit.

use Illuminate\Foundation\Testing\TestCase;
use Symfony\Component\BrowserKit\Client;

class BrowserKitTestCase extends TestCase
{
    protected function createBrowserClient(): Client
    {
        return new Client($this->app->make('http.client'));
    }
}

public function testWithLaravelIntegration()
{
    $client = $this->createBrowserClient();
    $client->request('GET', '/dashboard');

    $this->assertTrue($client->getHistory()->isFirstPage());
    $this->assertSelectorTextContains('h1', 'Welcome');
}

3. Handling Forms and Files

Pattern: Submit forms with files (e.g., uploads).

public function testFileUpload()
{
    $client = new Client(new CurlHttpClient());
    $client->request('GET', '/upload');

    $form = $client->getCrawler()->selectButton('Upload')->form();
    $form['file'] = new \Symfony\Component\HttpFoundation\File\UploadedFile(
        __DIR__.'/test.txt',
        'test.txt',
        'text/plain',
        null,
        true
    );

    $client->submit($form);
    $this->assertStringContainsString('File uploaded', $client->getResponse()->getContent());
}

4. Testing Redirects and History

Pattern: Validate navigation paths.

public function testRedirectAfterLogin()
{
    $client = new Client(new CurlHttpClient());
    $client->request('GET', '/login');
    $client->submitForm('Login', [
        'email' => 'user@example.com',
        'password' => 'password',
    ]);

    $history = $client->getHistory();
    $this->assertSame('/dashboard', $history->current()->getUri());
    $this->assertEquals(3, $history->count()); // Initial + login + redirect
}

5. Cookie and Session Management

Pattern: Simulate logged-in users.

public function testCookiePersistence()
{
    $client = new Client(new CurlHttpClient());
    $client->request('GET', '/login');
    $client->submitForm('Login', ['email' => 'user@example.com', 'password' => 'password']);

    // Visit another page (cookies persist)
    $client->request('GET', '/profile');
    $this->assertTrue($client->getCookie('XSRF-TOKEN')->isSecure());
}

6. Testing HTML Fragments

Pattern: Extract and validate parts of a page.

public function testFragmentValidation()
{
    $client = new Client(new CurlHttpClient());
    $client->request('GET', '/dashboard');

    $crawler = $client->getCrawler();
    $fragment = $crawler->filter('.user-stats')->html();
    $this->assertStringContainsString('Orders: 5', $fragment);
}

7. PHPUnit Constraints

Pattern: Use Symfony’s PHPUnit helpers.

use Symfony\Component\BrowserKit\Tests\Constraint\BrowserHistoryIsOnLastPage;

public function testPagination()
{
    $client = new Client(new CurlHttpClient());
    $client->request('GET', '/posts');

    $this->assertThat(
        $client->getHistory(),
        new BrowserHistoryIsOnLastPage()
    );
}

Gotchas and Tips

Pitfalls

  1. CSRF Tokens:

    • Issue: Forms with CSRF tokens may fail if not included.
    • Fix: Extract tokens from the page first:
      $token = $client->getCrawler()->filter('input[name="_token"]')->attr('value');
      $form['_token'] = $token;
      
  2. File Uploads:

    • Issue: Empty file fields break submissions.
    • Fix: Use new \Symfony\Component\HttpFoundation\File\UploadedFile() with null for empty fields (fixed in v7.2.4+).
  3. Relative URLs:

    • Issue: Links like /profile may break if the base URL isn’t set.
    • Fix: Use absolute URLs or set the client’s base URI:
      $client->setServerParameter('HTTP_HOST', 'example.test');
      
  4. Cookie Expiration:

    • Issue: Integer expiration values (e.g., time() + 3600) may fail.
    • Fix: Use DateTime or DateTimeImmutable (supported in v7.4.3+).
  5. History Tracking:

    • Issue: Redirects may not appear in history if not followed.
    • Fix: Use ->followRedirects(true) or manually chain requests.
  6. JavaScript-Rendered Content:

    • Issue: BrowserKit won’t execute JS (e.g., SPAs, dynamic content).
    • Fix: Use Laravel Dusk or Playwright for JS-heavy apps.
  7. PHP 8.4+ Features:

    • Issue: Native HTML5 parsing may break legacy HTML.
    • Fix: Disable with DomCrawler::setHtml($html, $baseUri, 'html5').

Debugging Tips

  1. Inspect Responses:

    $response = $client->getResponse();
    $this->assertSame(200, $response->getStatusCode());
    $this->assertStringContainsString('Expected text', $response->getContent());
    
  2. Dump Crawler:

    $crawler = $client->getCrawler();
    dump($crawler->html()); // View raw HTML
    
  3. Enable Verbose Logging:

    $client = new Client(new CurlHttpClient(), [], [
        'debug' => true,
    ]);
    
  4. Check Headers:

    $headers = $client->getResponse()->headers->all();
    $this->assertArrayHasKey('Set-Cookie', $headers);
    

Configuration Quirks

  1. HttpClient Configuration:

    • Tip: Reuse Laravel’s Http client for consistency:
      $client = new Client($this->app->make('http.client'));
      
  2. Base URI:

    • Tip: Set the base URI to avoid relative URL issues:
      $client->setServerParameter('HTTP_HOST', 'app.test');
      $client->setServerParameter('REQUEST_URI', '/');
      
  3. Server Parameters:

    • Tip: Simulate server environment:
      $client->setServerParameter('SERVER_NAME', 'localhost');
      
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation
uri-template/tests