jeffersongoncalves / pest-plugin-database-migrations
Load a package's migrations in tests in the exact order declared by its spatie/laravel-package-tools ServiceProvider
Package info
github.com/jeffersongoncalves/pest-plugin-database-migrations
pkg:composer/jeffersongoncalves/pest-plugin-database-migrations
Requires
- php: ^8.2
- illuminate/support: ^11.0|^12.0|^13.0
- spatie/laravel-package-tools: ^1.15
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.24
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Pest Plugin Database Migrations
Load a Laravel package's migrations in your tests in the exact order declared by its
ServiceProvider. The provider's hasMigrations() list is the truth; the test suite just
reads it.
Packages built with spatie/laravel-package-tools
ship migrations without timestamps, usually as .php.stub, and declare the run order in the
provider:
$package->hasMigrations([ 'create_kb_categories_table', 'create_kb_articles_table', 'create_kb_article_versions_table', 'create_kb_article_feedback_table', 'create_kb_article_relations_table', 'add_kb_content_localization', 'add_kb_collections', ]);
Laravel's migrator ignores that order and sorts files by name. create_kb_article_versions_table
sorts before create_kb_articles_table (_ < s in ASCII), which sorts before
create_kb_categories_table it references. SQLite doesn't enforce foreign keys at
CREATE TABLE time, so the suite passes locally, then breaks on MySQL/PostgreSQL. The usual
fixes are all bad: copying stubs around in defineDatabaseMigrations(), or keeping a second,
hand-maintained list of migration names in TestCase that drifts every time the package gains
a migration. This package reads the list straight from the ServiceProvider, so there is
nothing to keep in sync.
Installation
You can install the package via composer:
composer require jeffersongoncalves/pest-plugin-database-migrations --dev
Usage
Orchestra Testbench
// tests/TestCase.php use Illuminate\Foundation\Testing\RefreshDatabase; use JeffersonGoncalves\KnowledgeBase\KnowledgeBaseServiceProvider; use JeffersonGoncalves\PestPluginDatabaseMigrations\LoadsPackageMigrations; use Orchestra\Testbench\TestCase as Orchestra; abstract class TestCase extends Orchestra { use LoadsPackageMigrations; use RefreshDatabase; protected function defineDatabaseMigrations(): void { $this->loadPackageMigrations(KnowledgeBaseServiceProvider::class); } }
// tests/Pest.php uses(Tests\TestCase::class)->in('Feature', 'Unit');
Before / after
What it replaces:
protected function defineDatabaseMigrations(): void { $migrationsPath = __DIR__.'/../vendor/jeffersongoncalves/laravel-knowledge-base/database/migrations'; if (is_dir($migrationsPath)) { foreach (glob($migrationsPath.'/*.php.stub') as $stub) { $migrationPath = str_replace('.php.stub', '.php', $stub); if (! file_exists($migrationPath)) { copy($stub, $migrationPath); } } $this->loadMigrationsFrom($migrationsPath); } }
protected function defineDatabaseMigrations(): void { $this->loadPackageMigrations(KnowledgeBaseServiceProvider::class); }
It works the same for a package's own test suite and for an app or package testing against a
dependency installed in vendor/ — the provider class is all it needs.
Multiple packages
Providers are loaded in the order you pass them, so a package can be migrated after the one it depends on:
$this->loadPackageMigrations( BaseServiceProvider::class, ExtensionServiceProvider::class, );
Without the trait
use JeffersonGoncalves\PestPluginDatabaseMigrations\PackageMigrations; // Ordered absolute paths of the declared migration files. PackageMigrations::files($app, KnowledgeBaseServiceProvider::class); // Stages them in a temp directory and returns it, ready for loadMigrationsFrom(). PackageMigrations::stage($app, KnowledgeBaseServiceProvider::class);
How it works
- Instantiates the provider and calls
configurePackage()to readmigrationFileNames— nothing is registered or booted. - Resolves each name to
database/migrations/{name}.php, falling back to{name}.php.stub, the same waylaravel-package-toolsdoes. - Copies them to
sys_get_temp_dir()/pest-plugin-database-migrations/<hash>/as0000_name.php,0001_name.php, … and hands that directory toloadMigrationsFrom(). Files are only rewritten when their content changes, so parallel test workers don't read half-written files, and leftovers from a previous order are removed.
A declared migration that can't be found throws a RuntimeException naming the migration
and the provider, instead of silently skipping it.
Known limitations
- Only
spatie/laravel-package-toolsproviders. The provider must extendSpatie\LaravelPackageTools\PackageServiceProviderand declare migrations withhasMigration()/hasMigrations(). discoversMigrations()is not supported. Discovered migrations have no declared order to read; load that directory withloadMigrationsFrom()directly.- Migration names in the
migrationstable get the numeric prefix (0001_create_kb_articles_table). Only relevant if a test asserts on those names.
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security
If you discover any security related issues, please email the author instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
