Skip to content

Commit 578d24a

Browse files
[11.x] Add the ability to skip migrations within tests (#54441)
* introduce WithoutMigration * helper function for running skipped migrations * style * allow for array of migrations * revert RefreshDatabase changes * add migrator test * revert RefreshDatabase entirely * test unsetting skipped migrations * test with an array * formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent b29fa77 commit 578d24a

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

src/Illuminate/Database/Events/NoPendingMigrations.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Illuminate\Database\Events;
44

5-
class NoPendingMigrations
5+
use Illuminate\Contracts\Database\Events\MigrationEvent;
6+
7+
class NoPendingMigrations implements MigrationEvent
68
{
79
/**
810
* The migration method that was called.

src/Illuminate/Database/Migrations/Migrator.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ class Migrator
8686
*/
8787
protected $output;
8888

89+
/**
90+
* The pending migrations to skip.
91+
*
92+
* @var list<string>
93+
*/
94+
protected static $withoutMigrations = [];
95+
8996
/**
9097
* Create a new migrator instance.
9198
*
@@ -142,12 +149,29 @@ public function run($paths = [], array $options = [])
142149
*/
143150
protected function pendingMigrations($files, $ran)
144151
{
152+
$migrationsToSkip = $this->migrationsToSkip();
153+
145154
return (new Collection($files))
146-
->reject(fn ($file) => in_array($this->getMigrationName($file), $ran))
155+
->reject(fn ($file) =>
156+
in_array($migrationName = $this->getMigrationName($file), $ran) ||
157+
in_array($migrationName, $migrationsToSkip)
158+
)
147159
->values()
148160
->all();
149161
}
150162

163+
/**
164+
* Get list of pending migrations to skip.
165+
*
166+
* @return list<string>
167+
*/
168+
protected function migrationsToSkip()
169+
{
170+
return (new Collection(self::$withoutMigrations))
171+
->map($this->getMigrationName(...))
172+
->all();
173+
}
174+
151175
/**
152176
* Run an array of migrations.
153177
*
@@ -598,6 +622,17 @@ public function paths()
598622
return $this->paths;
599623
}
600624

625+
/**
626+
* Set the pending migrations to skip.
627+
*
628+
* @param list<string> $migrations
629+
* @return void
630+
*/
631+
public static function withoutMigrations(array $migrations)
632+
{
633+
static::$withoutMigrations = $migrations;
634+
}
635+
601636
/**
602637
* Get the default connection name.
603638
*

src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Console\Application as Artisan;
77
use Illuminate\Cookie\Middleware\EncryptCookies;
88
use Illuminate\Database\Eloquent\Model;
9+
use Illuminate\Database\Migrations\Migrator;
910
use Illuminate\Foundation\Bootstrap\HandleExceptions;
1011
use Illuminate\Foundation\Bootstrap\RegisterProviders;
1112
use Illuminate\Foundation\Console\AboutCommand;
@@ -170,6 +171,7 @@ protected function tearDownTheTestEnvironment(): void
170171
ConvertEmptyStringsToNull::flushState();
171172
EncryptCookies::flushState();
172173
HandleExceptions::flushState();
174+
Migrator::withoutMigrations([]);
173175
Once::flush();
174176
PreventRequestsDuringMaintenance::flushState();
175177
Queue::createPayloadUsing(null);

tests/Integration/Migration/MigratorTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Illuminate\Tests\Integration\Migration;
44

5+
use Illuminate\Database\Migrations\Migrator;
56
use Illuminate\Database\Schema\Blueprint;
67
use Illuminate\Support\Facades\DB;
78
use Illuminate\Support\Facades\Schema;
@@ -29,6 +30,12 @@ protected function setUp(): void
2930
$this->subject->getRepository()->createRepository();
3031
}
3132

33+
protected function tearDown(): void
34+
{
35+
parent::tearDown();
36+
Migrator::withoutMigrations([]);
37+
}
38+
3239
public function testMigrate()
3340
{
3441
$this->expectInfo('Running migrations.');
@@ -58,6 +65,24 @@ public function testMigrateWithoutOutput()
5865
$this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'last_name'));
5966
}
6067

68+
public function testWithSkippedMigrations()
69+
{
70+
$this->app->forgetInstance('migrator');
71+
$this->subject = $this->app->make('migrator');
72+
73+
Migrator::withoutMigrations(['2015_10_04_000000_modify_people_table.php', '2016_10_04_000000_modify_people_table']);
74+
75+
$this->subject->run([__DIR__.'/fixtures']);
76+
$this->assertTrue(DB::getSchemaBuilder()->hasTable('people'));
77+
$this->assertFalse(DB::getSchemaBuilder()->hasColumn('people', 'first_name'));
78+
$this->assertFalse(DB::getSchemaBuilder()->hasColumn('people', 'last_name'));
79+
80+
Migrator::withoutMigrations([]);
81+
$this->subject->run([__DIR__.'/fixtures']);
82+
$this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'first_name'));
83+
$this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'last_name'));
84+
}
85+
6186
public function testRollback()
6287
{
6388
$this->getConnection()->statement('CREATE TABLE people(id INT, first_name VARCHAR, last_name VARCHAR);');

0 commit comments

Comments
 (0)