Installation:
composer require --dev behat/mink
Mink is primarily used with Behat, but can be standalone for testing. For Laravel, pair it with behat/behat and mink-browserkit-driver (for testing HTTP requests) or mink-selenium-driver (for browser automation).
Basic Configuration (in behat.yml or standalone PHP):
default:
extensions:
Behat\MinkExtension:
base_url: 'http://your-laravel-app.test'
browser_name: 'chrome'
goutte: ~ # For simple HTTP testing (no JS)
selenium2: ~ # For browser automation (requires Selenium server)
First Use Case:
Test a Laravel route with GoutteDriver (no JS):
use Behat\Mink\Session;
use Behat\Mink\Driver\GoutteDriver;
$client = new \GuzzleHttp\Client();
$driver = new GoutteDriver($client);
$session = new Session($driver);
$session->start();
$session->visit('/login');
$session->getPage()->fillField('email', 'user@example.com');
$session->getPage()->pressButton('Login');
Testing Auth Routes: Use Mink to simulate login flows with Laravel’s session handling:
$session->visit('/login');
$session->getPage()->fillField('email', 'user@example.com');
$session->getPage()->fillField('password', 'secret');
$session->getPage()->pressButton('Login');
// Assert session cookie is set (Laravel's auth cookie)
$cookies = $session->getCookieJar()->all();
assert(array_key_exists('laravel_session', $cookies));
Integration with Laravel’s HTTP Tests:
Combine Mink with Laravel’s Testing facade for hybrid testing:
use Illuminate\Foundation\Testing\TestCase;
class ExampleTest extends TestCase {
public function testWithMink() {
$this->app->make('mink')->getSession()->visit('/dashboard');
$this->assertEquals('Dashboard', $this->app->make('mink')->getSession()->getPage()->getTitle());
}
}
Selenium for JavaScript-Heavy Apps:
Configure Selenium in behat.yml:
selenium2:
wd_host: "http://localhost:4444/wd/hub"
Then use it in tests:
$session = $this->getSession('selenium2');
$session->visit('/dashboard');
$session->wait(3000); // Wait for JS to load
Data-Driven Testing: Use Mink with Behat’s Gherkin syntax to externalize test cases:
Feature: User Login
Scenario: Successful login
Given I am on the "/login" page
When I fill in "email" with "user@example.com"
And I fill in "password" with "secret"
And I press "Login"
Then I should see "Dashboard"
Session Management:
TestResponse or HttpClient. Use getCookieJar() to inspect or manually set cookies.$session->getCookieJar()->set('laravel_session', $laravelSessionCookie);
Selenium Dependencies:
selenium/standalone-chrome).docker-compose.yml to spin up Selenium:
services:
selenium:
image: selenium/standalone-chrome
ports:
- "4444:4444"
Goutte Limitations:
Http tests.Headless Mode:
--headless) may miss visual issues (e.g., overlapping elements).xvfb (X virtual framebuffer):
xvfb-run --server-args="-screen 0, 1280x800x24" behat
Slow Tests:
wait() sparingly and prefer Goutte for non-JS paths.mink-parallel-testrunner for parallel execution.Inspect the Page:
$html = $session->getPage()->getHtml();
file_put_contents('debug.html', $html); // Save to file
Enable Mink’s Debug Output:
$session->getDriver()->setDebug(true);
Laravel-Specific Debugging:
dd(session()->all());
dd($session->getCookieJar()->all(), session()->getCookieJar()->get('laravel_session'));
Custom Drivers:
Extend Mink\Driver\DriverInterface for Laravel-specific needs (e.g., Laravel’s HttpClient).
Example:
class LaravelDriver implements DriverInterface {
public function visit($uri) {
$response = app('http')->get($uri);
// Parse response into Mink's Page object
}
}
Behat Contexts: Create reusable contexts for Laravel-specific interactions:
use Behat\Behat\Context\Context;
use Behat\Mink\Mink;
class LaravelContext implements Context {
private $mink;
public function __construct(Mink $mink) {
$this->mink = $mink;
}
/**
* @Given I am logged in as :user
*/
public function iAmLoggedInAs($user) {
$session = $this->mink->getSession();
$session->visit('/login');
// ... login logic
}
}
Hooks for Laravel: Use Behat hooks to set up Laravel’s app:
use Behat\Behat\Event\SuiteEvent;
use Behat\Behat\Hook\Scope\BeforeSuiteScope;
$eventDispatcher->addListener(
SuiteEvent::BEFORE_SUITE,
function (SuiteEvent $event) {
$kernel = require __DIR__.'/../bootstrap/app.php';
$app = $kernel->getContainer();
// Configure app for testing (e.g., set queue worker to "sync")
}
);
How can I help you explore Laravel packages today?