Reproduction repository for: laravel/framework#57716
When using RefreshDatabase trait with SQLite in-memory database, tests fail with "no such table" errors after a test that performs a transaction rollback.
composer install
cp .env.example .env
php artisan key:generate
php artisan testExpected: All 6 tests pass ✅
Actual (without the fix):
✓ Test 1: before exception - PASSES
✓ Test 2: before exception 2 - PASSES
✓ Test 3: throws exception and breaks connection - PASSES
✓ Test 4: first after exception - PASSES
✗ Test 5: second after exception - FAILS ❌
✗ Test 6: third after exception - FAILS ❌
Error message:
SQLSTATE[HY000]: General error: 1 no such table: users
This is the key to understanding the bug:
Test 3:
- Performs
DB::rollBack() - Connection exits transaction state
- Sets
RefreshDatabaseState::$migrated = false
Test 4:
- Calls
refreshTestDatabase() - Since
$migrated = false, runsmigrateDatabases() - Creates NEW PDO connection with fresh tables
- ✅ Test passes using this new connection
- Next tests,
beginDatabaseTransaction()callsrestoreInMemoryDatabase():
protected function restoreInMemoryDatabase()
{
foreach ($this->connectionsToTransact() as $name) {
if (isset(RefreshDatabaseState::$inMemoryConnections[$name])) {
// ⚠️ This overwrites the NEW PDO with the OLD stale PDO!
$database->connection($name)->setPdo(
RefreshDatabaseState::$inMemoryConnections[$name]
);
}
}
}Tests 5-6:
- Now using the OLD PDO (restored by
restoreInMemoryDatabase()) - Old PDO doesn't have any tables
- ❌ Tests fail with "no such table: users"
The problem occurs in this sequence:
- Test 3 performs rollback → connection not in transaction
beginDatabaseTransaction()detects this and setsRefreshDatabaseState::$migrated = false- Test 4 triggers re-migration, creating a NEW PDO with tables
- Test 4 passes ✅
restoreInMemoryDatabase()overwrites the new PDO with the old stale PDO fromRefreshDatabaseState::$inMemoryConnections- Tests 5+ fail because they're using the old PDO without tables ❌
The core issue: RefreshDatabaseState::$inMemoryConnections is never updated after re-migration, so restoreInMemoryDatabase() keeps restoring the wrong (stale) PDO instance.
The PR adds a call to updateInMemoryConnections() after migrateDatabases():
protected function refreshTestDatabase()
{
if (! RefreshDatabaseState::$migrated) {
$this->migrateDatabases();
$this->app[Kernel::class]->setArtisan(null);
// 🔧 Update the cached PDO references with new connections
$this->updateInMemoryConnections();
RefreshDatabaseState::$migrated = true;
}
$this->beginDatabaseTransaction();
}
protected function updateInMemoryConnections()
{
$database = $this->app->make('db');
foreach ($this->connectionsToTransact() as $name) {
if ($this->usingInMemoryDatabase($name)) {
$connection = $database->connection($name);
// Update cache with current PDO reference
RefreshDatabaseState::$inMemoryConnections[$name] = $connection->getPdo();
}
}
}This ensures that after re-migration, the cached PDO references point to the new connections with migrated tables, so restoreInMemoryDatabase() restores the correct connection.
This reproduction uses SQLite in-memory database configured in config/database.php:
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
],Or in .env:
DB_CONNECTION=sqlite
DB_DATABASE=:memory:app/Services/TestService.php- Service that simulates transaction rollbacktests/Feature/TestServiceTest.php- Test suite that reproduces the bugdatabase/migrations/- Standard Laravel user migration
The bug exists in these Laravel framework files:
Illuminate\Foundation\Testing\RefreshDatabaseIlluminate\Foundation\Testing\RefreshDatabaseState