Laravel Dusk, how to destroy session data between tests
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Laravel Dusk: Mastering Session Isolation for Independent Tests
When moving into end-to-end testing with tools like Laravel Dusk, developers often encounter a common hurdle: managing state. Unlike pure unit tests where objects are instantiated and destroyed in memory, browser automation involves interacting with an external system (the web server). This means session data, cookies, and authenticated states can persist between test runs if not explicitly managed.
The scenario you presented—where the first test implicitly logs a user in, affecting the second test—is a classic example of state leakage in integration testing. Understanding how to achieve true test isolation is crucial for writing reliable, maintainable suites. Let's dive into why this happens and explore the best ways to destroy or isolate session data within your Dusk tests.
The Challenge of Statefulness in Browser Testing
Laravel Dusk operates by simulating a real user navigating the application through a browser instance. When you perform actions like logging in, the server establishes a session, and that state is stored on the client side (via cookies) and the server side (via sessions). If subsequent tests reuse the same underlying browser context without clearing this state, they inherit the previous session, leading to unpredictable failures.
Your observation that calling $browser->visit('/admin/logout') works confirms that manually resetting the session is a solution. However, relying on manual cleanup within every test method can become cumbersome and brittle. The goal in robust testing is to make tests self-contained and independent of each other.
Solution 1: Manual Cleanup (The Direct Approach)
As you discovered, explicitly logging out (logout) before starting a new interaction forces the session state to reset for that specific browser instance.
public function testLoginFailure()
{
$this->browse(function (Browser $browser){
// Explicitly log out to clear the session state
$browser->visit('/admin/logout');
$browser->visit('/admin')
->type('email', 'someshit@afakedomain.com')
// ... rest of the test
});
}
Advantage: Simple to implement and immediately solves the state issue for that specific browser session.
Disadvantage: It couples your test logic directly to the application's specific logout endpoint, making the test less abstract and harder to read. It also relies on the assumption that /admin/logout is always the correct way to clear authentication in every scenario you might encounter.
Solution 2: Browser Isolation (The Best Practice)
The superior approach for ensuring complete isolation between tests is to treat each browser interaction as a fresh start. This is achieved by leveraging Dusk's ability to create multiple, isolated browser instances within a single test method using the createBrowsersFor method.
By creating a new browser instance for each test case, you guarantee that no session data from one test can leak into another. This aligns perfectly with the principles of clean separation in modern application development, whether dealing with Eloquent models or HTTP requests, as emphasized by best practices found on platforms like laravelcompany.com.
Here is how you would refactor your test to achieve true isolation:
public function testLoginFailure()
{
$this->createBrowsersFor(function (Browser $browser) {
// This browser instance starts completely fresh, without any previous session data.
$browser->visit('/admin')
->type('email', 'someshit@afakedomain.com')
->type('password', 'somefakepasswordthatdoesntwork')
->press('Login')
->assertSee('These credentials do not match our records.');
});
}
Advantages and Disadvantages of Isolation
| Feature | Manual Logout (visit('/logout')) |
Browser Isolation (createBrowsersFor) |
|---|---|---|
| Isolation Level | Session-specific reset. | Full browser context reset (cookies, sessions, history). |
| Readability | Low—requires knowing the specific cleanup steps. | High—the intent is clear: "start a new session." |
| Maintainability | Poor; brittle if session handling changes. | Excellent; robust against future state changes. |
| Performance | Slightly slower due to extra HTTP requests. | Minimal overhead, highly efficient for isolation. |
Conclusion
For building resilient end-to-end tests with Laravel Dusk, browser isolation using $this->createBrowsersFor() is the recommended practice. While manually logging out works, it treats the problem as session management rather than test isolation. By creating a fresh browser instance for each complex interaction, you ensure that your tests are truly independent, repeatable, and reflective of isolated user scenarios. This approach ensures that your testing layer remains robust, regardless of how complex your application's session handling becomes.