From 91fe23f97f4473a2256271fcf91cc44594de96b8 Mon Sep 17 00:00:00 2001 From: Jasper Tey Date: Thu, 28 Mar 2024 17:02:27 -0400 Subject: [PATCH] Update tests. --- composer.json | 8 +- tests/Autoload/CommandTest.php | 44 +++++++ tests/Autoload/FactoryTest.php | 62 +++++++--- tests/InstallTest.php | 7 ++ tests/TestCase.php | 107 +++++++++++++++--- .../Database/Factories/InvoiceFactory.php | 13 +++ .../Domain/Invoicing/Models/Payment.php | 9 ++ .../factories/Invoicing/InvoiceFactory.php | 13 +++ .../factories/Invoicing/PaymentFactory.php | 13 +++ .../factories/VanillaModelFactory.php | 13 +++ 10 files changed, 256 insertions(+), 33 deletions(-) create mode 100644 tests/resources/Domain/Invoicing/Database/Factories/InvoiceFactory.php create mode 100644 tests/resources/Domain/Invoicing/Models/Payment.php create mode 100644 tests/resources/database/factories/Invoicing/InvoiceFactory.php create mode 100644 tests/resources/database/factories/Invoicing/PaymentFactory.php create mode 100644 tests/resources/database/factories/VanillaModelFactory.php diff --git a/composer.json b/composer.json index 2594bd3..c1ae6cc 100644 --- a/composer.json +++ b/composer.json @@ -44,10 +44,10 @@ "autoload-dev": { "psr-4": { "Lunarstorm\\LaravelDDD\\Tests\\": "tests", - "App\\": "vendor/orchestra/testbench-core/laravel/app/", - "Database\\Factories\\": "vendor/orchestra/testbench-core/laravel/database/factories/", - "Database\\Seeders\\": "vendor/orchestra/testbench-core/laravel/database/seeders/", - "Domain\\": "vendor/orchestra/testbench-core/laravel/src/Domain/" + "App\\": "vendor/orchestra/testbench-core/laravel/app", + "Database\\Factories\\": "vendor/orchestra/testbench-core/laravel/database/factories", + "Database\\Seeders\\": "vendor/orchestra/testbench-core/laravel/database/seeders", + "Domain\\": "vendor/orchestra/testbench-core/laravel/src/Domain" } }, "scripts": { diff --git a/tests/Autoload/CommandTest.php b/tests/Autoload/CommandTest.php index fb0aab1..6a8edd6 100644 --- a/tests/Autoload/CommandTest.php +++ b/tests/Autoload/CommandTest.php @@ -2,6 +2,7 @@ use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Config; +use Illuminate\Support\Facades\File; use Lunarstorm\LaravelDDD\Support\DomainAutoloader; use Symfony\Component\Console\Exception\CommandNotFoundException; @@ -33,4 +34,47 @@ Artisan::call('invoice:deliver'); expect(Artisan::output())->toContain('Invoice delivered!'); }); + + it('recognizes new commands created afterwards', function () { + expect(class_exists('Domain\Invoicing\Commands\InvoiceVoid'))->toBeFalse(); + + Artisan::call('ddd:command', [ + 'name' => 'InvoiceVoid', + '--domain' => 'Invoicing', + ]); + + $filepath = base_path('src/Domain/Invoicing/Commands/InvoiceVoid.php'); + + expect(file_exists($filepath))->toBeTrue(); + + $class = 'Domain\Invoicing\Commands\InvoiceVoid'; + + // dd( + // [ + // // pre-created files work fine + // 'App\Models\User' => [ + // 'path' => base_path('app/Models/User.php'), + // 'file_exists' => file_exists(base_path('app/Models/User.php')), + // 'class_exists' => class_exists('App\Models\User'), + // ], + + // 'Domain\Invoicing\Models\Invoice' => [ + // 'path' => base_path('src/Domain/Invoicing/Models/Invoice.php'), + // 'file_exists' => file_exists(base_path('src/Domain/Invoicing/Models/Invoice.php')), + // 'class_exists' => class_exists('Domain\Invoicing\Models\Invoice'), + // ], + + // // but runtime-created class created but not recognized by class_exists + // $class => [ + // 'path' => $filepath, + // 'file_exists' => file_exists($filepath), + // 'class_exists' => class_exists($class), + // ], + // ], + // ); + + $instance = new $class(); + + expect(class_exists($class))->toBeTrue(); + })->markTestIncomplete("Can't get this to work under test environment"); }); diff --git a/tests/Autoload/FactoryTest.php b/tests/Autoload/FactoryTest.php index 3079a85..cdae53e 100644 --- a/tests/Autoload/FactoryTest.php +++ b/tests/Autoload/FactoryTest.php @@ -8,24 +8,58 @@ $this->setupTestApplication(); Config::set('ddd.domain_namespace', 'Domain'); - - (new DomainAutoloader())->autoload(); }); -it('can autoload domain factory', function ($modelClass, $expectedFactoryClass) { - expect($modelClass::factory())->toBeInstanceOf($expectedFactoryClass); -})->with([ - ['Domain\Invoicing\Models\VanillaModel', 'Domain\Invoicing\Database\Factories\VanillaModelFactory'], - ['Domain\Internal\Reporting\Models\Report', 'Domain\Internal\Reporting\Database\Factories\ReportFactory'], -]); +describe('autoload enabled', function () { + beforeEach(function () { + Config::set('ddd.autoload.factories', true); + + $this->afterApplicationCreated(function () { + (new DomainAutoloader())->autoload(); + }); + }); + + it('can resolve domain factory', function ($modelClass, $expectedFactoryClass) { + expect($modelClass::factory())->toBeInstanceOf($expectedFactoryClass); + })->with([ + // VanillaModel is a vanilla eloquent model in the domain layer + ['Domain\Invoicing\Models\VanillaModel', 'Domain\Invoicing\Database\Factories\VanillaModelFactory'], + + // Invoice has a factory both in the domain layer and the old way, but domain layer should take precedence + ['Domain\Invoicing\Models\Invoice', 'Domain\Invoicing\Database\Factories\InvoiceFactory'], + + // Payment has a factory not in the domain layer (the old way) + ['Domain\Invoicing\Models\Payment', 'Database\Factories\Invoicing\PaymentFactory'], -it('gracefully falls back for non-domain factories', function () { - Artisan::call('make:model RegularModel -f'); + // A subdomain Internal\Reporting scenario + ['Domain\Internal\Reporting\Models\Report', 'Domain\Internal\Reporting\Database\Factories\ReportFactory'], + ]); + + it('gracefully falls back for non-domain factories', function () { + Artisan::call('make:model RegularModel -f'); + + $modelClass = 'App\Models\RegularModel'; + + expect(class_exists($modelClass))->toBeTrue(); + + expect($modelClass::factory()) + ->toBeInstanceOf('Database\Factories\RegularModelFactory'); + }); +}); - $modelClass = 'App\Models\RegularModel'; +describe('autoload disabled', function () { + beforeEach(function () { + Config::set('ddd.autoload.factories', false); - expect(class_exists($modelClass))->toBeTrue(); + $this->afterApplicationCreated(function () { + (new DomainAutoloader())->autoload(); + }); + }); - expect($modelClass::factory()) - ->toBeInstanceOf('Database\Factories\RegularModelFactory'); + it('cannot resolve factories that rely on autoloading', function ($modelClass) { + $modelClass::factory(); + })->throws(\Error::class)->with([ + ['Domain\Invoicing\Models\VanillaModel'], + ['Domain\Internal\Reporting\Models\Report'], + ]); }); diff --git a/tests/InstallTest.php b/tests/InstallTest.php index ae94877..dcb58e1 100644 --- a/tests/InstallTest.php +++ b/tests/InstallTest.php @@ -25,6 +25,13 @@ }); it('can initialize composer.json', function ($domainPath, $domainRoot) { + $this->updateComposer( + forget: [ + ['autoload', 'psr-4', 'Domains\\'], + ['autoload', 'psr-4', 'Domain\\'], + ] + ); + Config::set('ddd.domain_path', $domainPath); Config::set('ddd.domain_namespace', $domainRoot); diff --git a/tests/TestCase.php b/tests/TestCase.php index 2ed3fab..fdddabe 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -18,21 +18,35 @@ protected function setUp(): void $this->cleanFilesAndFolders(); - $composerFile = base_path('composer.json'); - $data = json_decode(file_get_contents($composerFile), true); - - // Reset the domain namespace - Arr::forget($data, ['autoload', 'psr-4', 'Domains\\']); - Arr::forget($data, ['autoload', 'psr-4', 'Domain\\']); - - // Set up the essential app namespaces - data_set($data, ['autoload', 'psr-4', 'App\\'], 'vendor/orchestra/testbench-core/laravel/app'); - data_set($data, ['autoload', 'psr-4', 'Database\\Factories\\'], 'vendor/orchestra/testbench-core/laravel/database/factories'); - data_set($data, ['autoload', 'psr-4', 'Database\\Seeders\\'], 'vendor/orchestra/testbench-core/laravel/database/seeders'); - - file_put_contents($composerFile, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + // $composerFile = base_path('composer.json'); + // $data = json_decode(file_get_contents($composerFile), true); + + // // Reset the domain namespace + // Arr::forget($data, ['autoload', 'psr-4', 'Domains\\']); + // Arr::forget($data, ['autoload', 'psr-4', 'Domain\\']); + + // // Set up the essential app namespaces + // data_set($data, ['autoload', 'psr-4', 'App\\'], 'vendor/orchestra/testbench-core/laravel/app'); + // data_set($data, ['autoload', 'psr-4', 'Database\\Factories\\'], 'vendor/orchestra/testbench-core/laravel/database/factories'); + // data_set($data, ['autoload', 'psr-4', 'Database\\Seeders\\'], 'vendor/orchestra/testbench-core/laravel/database/seeders'); + + // file_put_contents($composerFile, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + + $this->updateComposer( + [ + [['autoload', 'psr-4', 'App\\'], 'vendor/orchestra/testbench-core/laravel/app'], + [['autoload', 'psr-4', 'Database\\Factories\\'], 'vendor/orchestra/testbench-core/laravel/database/factories'], + [['autoload', 'psr-4', 'Database\\Seeders\\'], 'vendor/orchestra/testbench-core/laravel/database/seeders'], + [['autoload', 'psr-4', 'Domain\\'], 'vendor/orchestra/testbench-core/laravel/src/Domain'], + ], + forget: [ + ['autoload', 'psr-4', 'Domains\\'], + ['autoload', 'psr-4', 'Domain\\'], + ] + ); - $this->composerReload(); + // This may not be needed after all (significantly slows down the tests) + // $this->composerReload(); Factory::guessFactoryNamesUsing( fn (string $modelName) => 'Lunarstorm\\LaravelDDD\\Database\\Factories\\'.class_basename($modelName).'Factory' @@ -43,6 +57,55 @@ protected function setUp(): void }); } + protected function getComposerFileContents() + { + return file_get_contents(base_path('composer.json')); + } + + protected function getComposerFileAsArray() + { + return json_decode($this->getComposerFileContents(), true); + } + + protected function updateComposerFileFromArray(array $data) + { + file_put_contents(base_path('composer.json'), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + + return $this; + } + + protected function updateComposer($set = [], $forget = []) + { + $data = $this->getComposerFileAsArray(); + + foreach ($forget as $key) { + Arr::forget($data, $key); + } + + foreach ($set as $pair) { + [$key, $value] = $pair; + data_set($data, $key, $value); + } + + $this->updateComposerFileFromArray($data); + + return $this; + } + + protected function forgetComposerValues($keys) + { + $composerFile = base_path('composer.json'); + $data = json_decode(file_get_contents($composerFile), true); + + foreach ($keys as $key) { + Arr::forget($data, $key); + } + + file_put_contents($composerFile, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + + return $this; + } + protected function getPackageProviders($app) { return [ @@ -80,11 +143,25 @@ protected function cleanFilesAndFolders() DomainAutoloader::clearCache(); } - public function setupTestApplication() + protected function setupTestApplication() { File::copyDirectory(__DIR__.'/resources/app', app_path()); + File::copyDirectory(__DIR__.'/resources/database', base_path('database')); File::copyDirectory(__DIR__.'/resources/Domain', base_path('src/Domain')); File::ensureDirectoryExists(app_path('Models')); + + $this->setDomainPathInComposer('Domain', 'src/Domain'); + } + + protected function setDomainPathInComposer($domainNamespace, $domainPath) + { + $this->updateComposer( + set: [ + [['autoload', 'psr-4', $domainNamespace.'\\'], $domainPath], + ], + ); + + return $this; } } diff --git a/tests/resources/Domain/Invoicing/Database/Factories/InvoiceFactory.php b/tests/resources/Domain/Invoicing/Database/Factories/InvoiceFactory.php new file mode 100644 index 0000000..9cad4a0 --- /dev/null +++ b/tests/resources/Domain/Invoicing/Database/Factories/InvoiceFactory.php @@ -0,0 +1,13 @@ +