symfony/browser-kit
Symfony BrowserKit simulates a web browser in PHP for testing and automation. Make requests, follow links, and submit forms programmatically, with a built-in implementation that uses Symfony HttpClient to perform real HTTP requests.
Installation:
composer require symfony/browser-kit
BrowserKit is a standalone component but works seamlessly with Laravel’s built-in HTTP clients (e.g., Guzzle, Symfony HttpClient).
First Use Case: Simulate a browser request to test a Laravel route:
use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;
$client = HttpClient::create();
$browser = new HttpBrowser($client);
// Navigate to a Laravel route
$browser->request('GET', 'http://your-laravel-app.test/login');
// Check response
$response = $browser->getResponse();
$content = $response->getContent();
Where to Look First:
History class for tracking navigation (e.g., $browser->getHistory()).DomCrawler integration for parsing HTML responses (included in Symfony’s DOM component).Replace manual testing or Laravel Dusk with BrowserKit for server-side rendered routes:
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\DomCrawler\Crawler;
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', '/dashboard');
// Assert content
$crawler = new Crawler($browser->getResponse()->getContent());
expect($crawler->filter('h1')->text())->toContain('Dashboard');
// Simulate form submission
$form = $crawler->selectButton('Submit')->form();
$browser->submit($form);
Extract structured data from Laravel-powered pages (e.g., admin panels):
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', '/admin/products', [
'auth' => ['[email protected]', 'password'],
]);
$crawler = new Crawler($browser->getResponse()->getContent());
$products = $crawler->filter('.product-card')->each(function (Crawler $node) {
return [
'name' => $node->filter('.name')->text(),
'price' => $node->filter('.price')->text(),
];
});
Add a pre-deploy check in Laravel Forge/Envoyer:
// In a Laravel Artisan command or Envoyer hook
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', 'https://staging-app.test/checkout');
// Verify critical elements
$this->assertTrue($browser->getHistory()->current()->getStatus() === 200);
$this->assertStringContainsString('Payment Successful', $browser->getResponse()->getContent());
Use BrowserKit in PHPUnit/Pest tests:
use Tests\TestCase;
use Symfony\Component\BrowserKit\HttpBrowser;
class CheckoutTest extends TestCase
{
public function testCheckoutFlow()
{
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', '/cart');
// Add item to cart (simulate user action)
$browser->clickLink('Add to Cart');
// Proceed to checkout
$browser->clickLink('Checkout');
$this->assertEquals(200, $browser->getHistory()->current()->getStatus());
}
}
Simulate login and form submissions:
$browser = new HttpBrowser(HttpClient::create());
// Login
$browser->request('GET', '/login');
$form = $browser->getCrawler()->selectButton('Login')->form([
'email' => '[email protected]',
'password' => 'password123',
]);
$browser->submit($form);
// Verify auth
$this->assertStringContainsString('Welcome', $browser->getResponse()->getContent());
Persist sessions across requests:
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', '/login'); // Set session cookie
// Subsequent requests reuse cookies
$browser->request('GET', '/dashboard');
$this->assertTrue($browser->getCookieJar()->has('laravel_session'));
Offload scraping to Laravel Queues:
use Illuminate\Support\Facades\Queue;
Queue::push(function () {
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', 'https://target-site.com/products');
// Process data and store in DB
$products = $browser->getCrawler()->filter('.product')->each(...);
Product::insert($products);
});
BrowserKit works with Laravel’s default HTTP client (Symfony HttpClient):
use Illuminate\Support\Facades\Http;
$browser = new HttpBrowser(Http::create());
Test static assets in CI:
$browser->request('GET', mix('assets/app.js'));
$this->assertEquals(200, $browser->getResponse()->getStatusCode());
Inspect BrowserKit requests in Laravel Telescope:
$browser->request('GET', '/admin');
Telescope::log('BrowserKit Request', [
'url' => $browser->getHistory()->current()->getUri(),
'status' => $browser->getResponse()->getStatusCode(),
]);
Add Laravel middleware to BrowserKit requests:
$client = HttpClient::create([
'headers' => [
'X-Custom-Header' => 'value',
],
'auth_basic' => ['user', 'pass'],
]);
$browser = new HttpBrowser($client);
Domain and Path attributes:
$browser->getCookieJar()->set('laravel_session', 'value', [
'domain' => '.yourdomain.test',
'path' => '/',
]);
$browser->getClient()->setOptions([
'max_redirects' => 3,
]);
submit() method with all required fields:
$form = $browser->getCrawler()->selectButton('Upload')->form([
'file' => null, // Handle empty files
'_token' => $browser->getCrawler()->filter('input[name="_token"]')->attr('value'),
]);
$browser->submit($form);
History object may not reflect expected navigation if requests fail silently.$history = $browser->getHistory();
$this->assertEquals(200, $history->current()->getStatus());
$browser->getClient()->on('request', function ($event) {
\Log::debug('Request:', [
'url' => $event->getRequest()->getUri(),
'headers' => $event->getRequest()->getHeaders(),
]);
});
$browser->getClient()->on('response', function ($event) {
\Log::debug('Response:', [
'status' => $event->getResponse()->getStatusCode(),
'content' => $event->getResponse()->getContent(false),
]);
});
How can I help you explore Laravel packages today?