From b431fb6f15adae45eeab925a85cadd023e4dce56 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Wed, 25 Jun 2025 15:49:05 +0300 Subject: [PATCH 01/17] refactor: use resource in generate only nova tests --- src/Commands/MakeEntityCommand.php | 15 +++++- src/Generators/NovaTestGenerator.php | 72 ++++++++++++++++++++-------- tests/NovaTestGeneratorTest.php | 47 +++++++++++++----- tests/Support/GeneratorMockTrait.php | 9 ++++ 4 files changed, 111 insertions(+), 32 deletions(-) diff --git a/src/Commands/MakeEntityCommand.php b/src/Commands/MakeEntityCommand.php index 680a28b4..e7ac1b66 100644 --- a/src/Commands/MakeEntityCommand.php +++ b/src/Commands/MakeEntityCommand.php @@ -55,6 +55,7 @@ class MakeEntityCommand extends Command {--only-seeder : Set this flag if you want to create only seeder.} {--only-nova-resource : Set this flag if you want to create only nova resource.} {--only-nova-tests : Set this flag if you want to create only nova resource tests.} + {resourceName? : The name of the Nova resource, used only with --only-nova-tests.} {--methods=CRUD : Set types of methods to create. Affect on routes, requests classes, controller\'s methods and tests methods.} @@ -213,7 +214,19 @@ protected function generate() protected function runGeneration($generator) { - app($generator) + $resourceName = "{$this->argument('name')}Resource"; + + if (!empty($this->argument('resourceName'))){ + $resourceName = $this->argument('resourceName'); + } + + $generatorInstance = app($generator); + + if (method_exists($generatorInstance, 'setResource')) { + $generatorInstance->setResource($resourceName); + } + + $generatorInstance ->setModel($this->argument('name')) ->setFields($this->getFields()) ->setRelations($this->getRelations()) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index 080336ba..64ab87d6 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -8,10 +8,14 @@ use RonasIT\Support\Events\SuccessCreateMessage; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Exceptions\ClassNotExistsException; +use RecursiveIteratorIterator; +use RecursiveDirectoryIterator; class NovaTestGenerator extends AbstractTestsGenerator { - protected $novaModelName; + protected string $novaResourceName; + + protected ?string $fullNovaResourcePath = null; public function generate(): void { @@ -19,16 +23,24 @@ public function generate(): void if (!$this->doesNovaResourceExists()) { $this->throwFailureException( ClassNotExistsException::class, - "Cannot create Nova{$this->model}Test cause {$this->model} Nova resource does not exist.", - "Create {$this->model} Nova resource." + "Cannot create Nova{$this->novaResourceName}Test cause {$this->novaResourceName} Nova resource does not exist.", + "Create {$this->novaResourceName} Nova resource." ); } - if ($this->classExists('nova', "Nova{$this->model}Test")) { + if ($this->classExists('nova', "Nova{$this->novaResourceName}Test")) { $this->throwFailureException( ClassAlreadyExistsException::class, - "Cannot create Nova{$this->model}Test cause it's already exist.", - "Remove Nova{$this->model}Test." + "Cannot create Nova{$this->novaResourceName}Test cause it's already exist.", + "Remove Nova{$this->novaResourceName}Test." + ); + } + + if (!$this->classExists('models', $this->model)) { + $this->throwFailureException( + ClassNotExistsException::class, + "Cannot create Nova{$this->novaResourceName}Test cause {$this->model} does not exist.", + "Create a {$this->model} Model by himself or run command 'php artisan make:entity {$this->model} --only-model'." ); } @@ -38,6 +50,13 @@ public function generate(): void } } + public function setResource($novaResourceName) + { + $this->novaResourceName = Str::studly($novaResourceName); + + return $this; + } + public function generateTests(): void { if (!$this->isStubExists('nova_test')) { @@ -58,9 +77,9 @@ public function generateTests(): void 'filters' => $filters, ]); - $this->saveClass('tests', "Nova{$this->model}Test", $fileContent); + $this->saveClass('tests', "Nova{$this->novaResourceName}Test", $fileContent); - event(new SuccessCreateMessage("Created a new Nova test: Nova{$this->model}Test")); + event(new SuccessCreateMessage("Created a new Nova test: Nova{$this->novaResourceName}Test")); } protected function getActions(): array @@ -83,22 +102,22 @@ protected function getActions(): array protected function loadNovaActions() { - return app("\\App\\Nova\\{$this->novaModelName}")->actions(new NovaRequest()); + return app("{$this->fullNovaResourcePath}")->actions(new NovaRequest()); } protected function loadNovaFields() { - return app("\\App\\Nova\\{$this->novaModelName}")->fields(new NovaRequest()); + return app("{$this->fullNovaResourcePath}")->fields(new NovaRequest()); } protected function loadNovaFilters() { - return app("\\App\\Nova\\{$this->novaModelName}")->filters(new NovaRequest()); + return app("{$this->fullNovaResourcePath}")->filters(new NovaRequest()); } public function getTestClassName(): string { - return "Nova{$this->model}Test"; + return "Nova{$this->novaResourceName}Test"; } protected function isFixtureNeeded($type): bool @@ -108,16 +127,13 @@ protected function isFixtureNeeded($type): bool protected function doesNovaResourceExists(): bool { - $possibleNovaModelNames = [ - "{$this->model}NovaResource", - "{$this->model}Resource", - $this->model - ]; + $novaDirectory = app_path('Nova'); - foreach ($possibleNovaModelNames as $modelName) { - if ($this->classExists('nova', $modelName)) { - $this->novaModelName = $modelName; + $allNovaClasses = $this->getAllNovaClasses($novaDirectory); + foreach ($allNovaClasses as $class) { + if (Str::contains($class, $this->novaResourceName)) { + $this->fullNovaResourcePath = $class; return true; } } @@ -125,6 +141,22 @@ protected function doesNovaResourceExists(): bool return false; } + protected function getAllNovaClasses(string $directory): array + { + $classes = []; + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); + + foreach ($iterator as $file) { + if ($file->isFile() && $file->getExtension() === 'php') { + $relativePath = str_replace(app_path() . DIRECTORY_SEPARATOR, '', $file->getPathname()); + $class = 'App\\' . str_replace(['/', '.php'], ['\\', ''], $relativePath); + $classes[] = $class; + } + } + + return $classes; + } + protected function collectFilters(): array { $filtersFromFields = $this->getFiltersFromFields(); diff --git a/tests/NovaTestGeneratorTest.php b/tests/NovaTestGeneratorTest.php index d953040a..e4ee5be5 100644 --- a/tests/NovaTestGeneratorTest.php +++ b/tests/NovaTestGeneratorTest.php @@ -2,7 +2,6 @@ namespace RonasIT\Support\Tests; -use RonasIT\Support\Tests\Support\Models\WelcomeBonus; use RonasIT\Support\Events\SuccessCreateMessage; use RonasIT\Support\Events\WarningEvent; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; @@ -10,6 +9,7 @@ use RonasIT\Support\Generators\NovaTestGenerator; use RonasIT\Support\Tests\Support\NovaTestGeneratorTest\NovaTestGeneratorMockTrait; use Laravel\Nova\NovaServiceProvider; +use RonasIT\Support\Tests\Support\Models\WelcomeBonus; use Mockery; class NovaTestGeneratorTest extends TestCase @@ -28,9 +28,7 @@ public function testGenerateResourceNotExists() $this->mockNovaServiceProviderExists(); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'PostNovaResource'], false), - $this->classExistsMethodCall(['nova', 'PostResource'], false), - $this->classExistsMethodCall(['nova', 'Post'], false), + $this->doesNovaResourceExistsCall(false), ]); $this->assertExceptionThrew( @@ -40,6 +38,7 @@ className: ClassNotExistsException::class, app(NovaTestGenerator::class) ->setModel('Post') + ->setResource('Post') ->generate(); } @@ -48,8 +47,7 @@ public function testGenerateNovaTestAlreadyExists() $this->mockNovaServiceProviderExists(); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'PostNovaResource']), - $this->classExistsMethodCall(['nova', 'NovaPostTest']) + $this->classExistsMethodCall(['nova', 'NovaPostTest']), ]); $this->assertExceptionThrew( @@ -59,23 +57,32 @@ className: ClassAlreadyExistsException::class, app(NovaTestGenerator::class) ->setModel('Post') + ->setResource('Post') ->generate(); } public function testNovaTestStubNotExist() { + config([ + 'entity-generator.paths.models' => 'RonasIT/Support/Tests/Support/Models', + 'entity-generator.stubs.nova_test' => 'incorrect_stub', + ]); + $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), ); - $this->mockNovaRequestClassCall(); - - config([ - 'entity-generator.paths.models' => 'RonasIT/Support/Tests/Support/Models', - 'entity-generator.stubs.nova_test' => 'incorrect_stub', + $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusTest'], false), + $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['models', 'User'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), ]); + $this->mockNovaRequestClassCall(); + $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); $mock ->shouldReceive('beginTransaction', 'rollBack') @@ -83,6 +90,7 @@ public function testNovaTestStubNotExist() app(NovaTestGenerator::class) ->setModel('WelcomeBonus') + ->setResource('WelcomeBonus') ->generate(); $this->assertFileDoesNotExist('tests/NovaWelcomeBonusTest.php'); @@ -108,8 +116,16 @@ public function testDumpStubNotExist() 'entity-generator.stubs.dump' => 'incorrect_stub', ]); + $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusTest'], false), + $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['models', 'User'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + ]); + app(NovaTestGenerator::class) ->setModel('WelcomeBonus') + ->setResource('WelcomeBonus') ->generate(); $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusTest.php'); @@ -130,6 +146,14 @@ public function testSuccess() 'entity-generator.paths.models' => 'RonasIT/Support/Tests/Support/Models', ]); + $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusTest'], false), + $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['models', 'User'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + ]); + $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); $mock ->shouldReceive('beginTransaction', 'rollBack') @@ -144,6 +168,7 @@ public function testSuccess() app(NovaTestGenerator::class) ->setModel('WelcomeBonus') + ->setResource('WelcomeBonus') ->generate(); $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusTest.php'); diff --git a/tests/Support/GeneratorMockTrait.php b/tests/Support/GeneratorMockTrait.php index 09ef73bc..65c6dda4 100644 --- a/tests/Support/GeneratorMockTrait.php +++ b/tests/Support/GeneratorMockTrait.php @@ -30,6 +30,15 @@ public function classExistsMethodCall(array $arguments, bool $result = true): ar ]; } + public function doesNovaResourceExistsCall(bool $result = true): array + { + return [ + 'function' => 'doesNovaResourceExists', + 'arguments' => [], + 'result' => $result + ]; + } + public function nativeClassExistsMethodCall(array $arguments, bool $result = true): array { return [ From 563f2c20ae975bee7ffb456d2fed0afabb08e244 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Fri, 27 Jun 2025 13:36:56 +0300 Subject: [PATCH 02/17] fix: tests --- tests/CommandTest.php | 53 ++++++++++++++++++++-- tests/Support/Command/CommandMockTrait.php | 41 ++++++++++++++++- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 8c90745e..4b011513 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -77,11 +77,11 @@ public function testCallCommand() $this->assertGeneratedFileEquals('update_request.json', 'tests/fixtures/PostTest/update_post_request.json'); $this->assertGeneratedFileEquals('validation.php', 'lang/en/validation.php'); $this->assertGeneratedFileEquals('nova_resource.php', 'app/Nova/PostResource.php'); - $this->assertGeneratedFileEquals('nova_test.php', 'tests/NovaPostTest.php'); - $this->assertGeneratedFileEquals('nova_dump.php', 'tests/fixtures/NovaPostTest/nova_post_dump.sql'); - $this->assertGeneratedFileEquals('create_request.json', 'tests/fixtures/NovaPostTest/create_post_request.json'); - $this->assertGeneratedFileEquals('create_response.json', 'tests/fixtures/NovaPostTest/create_post_response.json'); - $this->assertGeneratedFileEquals('update_request.json', 'tests/fixtures/NovaPostTest/update_post_request.json'); + $this->assertGeneratedFileEquals('nova_test.php', 'tests/NovaPostResourceTest.php'); + $this->assertGeneratedFileEquals('nova_dump.php', 'tests/fixtures/NovaPostResourceTest/nova_post_dump.sql'); + $this->assertGeneratedFileEquals('create_request.json', 'tests/fixtures/NovaPostResourceTest/create_post_request.json'); + $this->assertGeneratedFileEquals('create_response.json', 'tests/fixtures/NovaPostResourceTest/create_post_response.json'); + $this->assertGeneratedFileEquals('update_request.json', 'tests/fixtures/NovaPostResourceTest/update_post_request.json'); } public function testMakeOnly() @@ -121,6 +121,49 @@ public function testMakeOnly() $this->assertFileDoesNotExist('tests/fixtures/NovaPostTest/update_post_request.json'); } + public function testMakeOnlyNovaTest(): void + { + $this->mockFilesystemWithPostModelAndResource(); + + config([ + 'entity-generator.paths.models' => 'RonasIT\Support\Tests\Support\Command\Models', + ]); + + $this->mockGeneratorOnlyNovaTests(); + + $this + ->artisan('make:entity Post PostResource --only-nova-tests') + ->assertSuccessful(); + + $this->assertFileDoesNotExist('app/Repositories/PostRepository.php'); + $this->assertFileDoesNotExist('database/migrations/2016_10_20_110500_posts_create_table.php'); + $this->assertFileDoesNotExist('database/factories/PostFactory.php'); + $this->assertFileDoesNotExist('database/seeders/PostSeeder.php'); + $this->assertFileDoesNotExist('app/Models/Post.php'); + $this->assertFileDoesNotExist('app/Services/PostService.php'); + $this->assertFileDoesNotExist('app/Http/Requests/Post/CreatePostRequest.php'); + $this->assertFileDoesNotExist('app/Http/Requests/Post/GetPostRequest.php'); + $this->assertFileDoesNotExist('app/Http/Requests/Post/SearchPostsRequest.php'); + $this->assertFileDoesNotExist('app/Http/Requests/Post/UpdatePostRequest.php'); + $this->assertFileDoesNotExist('app/Http/Requests/Post/DeletePostRequest.php'); + $this->assertFileDoesNotExist('app/Http/Controllers/PostController.php'); + $this->assertFileDoesNotExist('app/Http/Resources/Post/PostResource.php'); + $this->assertFileDoesNotExist('app/Http/Resources/Post/PostsCollectionResource.php'); + $this->assertFileDoesNotExist('routes/api.php'); + $this->assertFileDoesNotExist('tests/PostTest.php'); + $this->assertFileDoesNotExist('tests/fixtures/PostTest/dump.sql'); + $this->assertFileDoesNotExist('tests/fixtures/PostTest/create_post_request.json'); + $this->assertFileDoesNotExist('tests/fixtures/PostTest/create_post_response.json'); + $this->assertFileDoesNotExist('tests/fixtures/PostTest/update_post_request.json'); + $this->assertFileDoesNotExist('lang/en/validation.php'); + $this->assertFileDoesNotExist('app/Nova/PostResource.php'); + $this->assertGeneratedFileEquals('nova_test.php', 'tests/NovaPostResourceTest.php'); + $this->assertGeneratedFileEquals('nova_dump.php', 'tests/fixtures/NovaPostResourceTest/nova_post_dump.sql'); + $this->assertGeneratedFileEquals('create_request.json', 'tests/fixtures/NovaPostResourceTest/create_post_request.json'); + $this->assertGeneratedFileEquals('create_response.json', 'tests/fixtures/NovaPostResourceTest/create_post_response.json'); + $this->assertGeneratedFileEquals('update_request.json', 'tests/fixtures/NovaPostResourceTest/update_post_request.json'); + } + public function testCallWithNotDefaultConfig() { $this->app->instance('path.base', $this->generatedFileBasePath); diff --git a/tests/Support/Command/CommandMockTrait.php b/tests/Support/Command/CommandMockTrait.php index b1c94412..57f54b6e 100644 --- a/tests/Support/Command/CommandMockTrait.php +++ b/tests/Support/Command/CommandMockTrait.php @@ -25,11 +25,22 @@ public function mockFilesystemPostModelExists(): void $fileSystemMock->setStructure(); } + public function mockFilesystemWithPostModelAndResource(): void + { + $fileSystemMock = new FileSystemMock(); + + $fileSystemMock->models = ['Post.php' => $this->mockPhpFileContent()]; + $fileSystemMock->novaModels = ['PostResource.php' => $this->mockPhpFileContent()]; + $fileSystemMock->config = ['entity-generator.php' => '']; + + $fileSystemMock->setStructure(); + } + public function mockFilesystem(): void { $fileSystemMock = new FileSystemMock(); - $fileSystemMock->routes = [ 'api.php' => $this->mockPhpFileContent()]; + $fileSystemMock->routes = ['api.php' => $this->mockPhpFileContent()]; $fileSystemMock->config = ['entity-generator.php' => '']; $fileSystemMock->translations = []; @@ -61,6 +72,34 @@ public function mockGenerator(): void ); } + public function mockGeneratorOnlyNovaTests(): void + { + $this->mockClass(NovaTestGenerator::class, [ + $this->functionCall( + name: 'loadNovaActions', + result: [], + ), + $this->functionCall( + name: 'loadNovaFields', + result: [], + ), + $this->functionCall( + name: 'loadNovaFilters', + result: [], + ), + $this->classExistsMethodCall(['nova', 'NovaPostResourceTest'], false), + $this->classExistsMethodCall(['models', 'Post']), + $this->classExistsMethodCall(['models', 'User'], false), + $this->classExistsMethodCall(['factories', 'PostFactory'], false), + $this->classExistsMethodCall(['factories', 'PostFactory'], false), + ]); + + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall(['Laravel\Nova\NovaServiceProvider', true]), + $this->nativeClassExistsMethodCall(['RonasIT\Support\Tests\Support\Command\Models\Post', true]), + ); + } + public function mockGettingModelInstance(): void { $connectionMock = Mockery::mock(Connection::class)->makePartial(); From 8a19c3a4e25d80ae7e996dbe5139587a2d455e5c Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Fri, 27 Jun 2025 14:20:38 +0300 Subject: [PATCH 03/17] fix:tests --- tests/Support/Command/CommandMockTrait.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Support/Command/CommandMockTrait.php b/tests/Support/Command/CommandMockTrait.php index 57f54b6e..19655363 100644 --- a/tests/Support/Command/CommandMockTrait.php +++ b/tests/Support/Command/CommandMockTrait.php @@ -94,6 +94,11 @@ public function mockGeneratorOnlyNovaTests(): void $this->classExistsMethodCall(['factories', 'PostFactory'], false), ]); + $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); + $mock + ->shouldReceive('beginTransaction', 'rollBack') + ->once(); + $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall(['Laravel\Nova\NovaServiceProvider', true]), $this->nativeClassExistsMethodCall(['RonasIT\Support\Tests\Support\Command\Models\Post', true]), From 33ca7bcc4d3aa9e6e43fd5111e720f53f0768251 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Fri, 27 Jun 2025 14:35:02 +0300 Subject: [PATCH 04/17] fix:Tests --- tests/CommandTest.php | 1 + tests/Support/Command/CommandMockTrait.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 4b011513..2b33b9a5 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -127,6 +127,7 @@ public function testMakeOnlyNovaTest(): void config([ 'entity-generator.paths.models' => 'RonasIT\Support\Tests\Support\Command\Models', + 'entity-generator.paths.factories' => 'RonasIT\Support\Tests\Support\Command\Factories', ]); $this->mockGeneratorOnlyNovaTests(); diff --git a/tests/Support/Command/CommandMockTrait.php b/tests/Support/Command/CommandMockTrait.php index 19655363..c0d3eee1 100644 --- a/tests/Support/Command/CommandMockTrait.php +++ b/tests/Support/Command/CommandMockTrait.php @@ -90,8 +90,8 @@ public function mockGeneratorOnlyNovaTests(): void $this->classExistsMethodCall(['nova', 'NovaPostResourceTest'], false), $this->classExistsMethodCall(['models', 'Post']), $this->classExistsMethodCall(['models', 'User'], false), - $this->classExistsMethodCall(['factories', 'PostFactory'], false), - $this->classExistsMethodCall(['factories', 'PostFactory'], false), + $this->classExistsMethodCall(['factories', 'PostFactory']), + $this->classExistsMethodCall(['factories', 'PostFactory']), ]); $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); From 516473bdd1ee43b6e0eb939fe1a5d19bfe306e40 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Fri, 27 Jun 2025 14:51:22 +0300 Subject: [PATCH 05/17] fix:tests --- tests/CommandTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 2b33b9a5..3ea0c840 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -123,6 +123,8 @@ public function testMakeOnly() public function testMakeOnlyNovaTest(): void { + Carbon::setTestNow('2016-10-20 11:05:00'); + $this->mockFilesystemWithPostModelAndResource(); config([ From b5d870d380912fa9389186b68897e19722020585 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Tue, 1 Jul 2025 17:06:12 +0300 Subject: [PATCH 06/17] refactor: change set resource from argument ot option --- src/Commands/MakeEntityCommand.php | 8 ++++---- tests/CommandTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Commands/MakeEntityCommand.php b/src/Commands/MakeEntityCommand.php index e7ac1b66..466593ec 100644 --- a/src/Commands/MakeEntityCommand.php +++ b/src/Commands/MakeEntityCommand.php @@ -55,8 +55,8 @@ class MakeEntityCommand extends Command {--only-seeder : Set this flag if you want to create only seeder.} {--only-nova-resource : Set this flag if you want to create only nova resource.} {--only-nova-tests : Set this flag if you want to create only nova resource tests.} - {resourceName? : The name of the Nova resource, used only with --only-nova-tests.} - + {--resource-name= : Override the default Nova resource name. Used only with --only-nova-tests.} + {--methods=CRUD : Set types of methods to create. Affect on routes, requests classes, controller\'s methods and tests methods.} {--i|integer=* : Add integer field to entity.} @@ -216,8 +216,8 @@ protected function runGeneration($generator) { $resourceName = "{$this->argument('name')}Resource"; - if (!empty($this->argument('resourceName'))){ - $resourceName = $this->argument('resourceName'); + if (!empty($this->option('resource-name'))){ + $resourceName = $this->option('resource-name'); } $generatorInstance = app($generator); diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 3ea0c840..3b4fe7c4 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -135,7 +135,7 @@ public function testMakeOnlyNovaTest(): void $this->mockGeneratorOnlyNovaTests(); $this - ->artisan('make:entity Post PostResource --only-nova-tests') + ->artisan('make:entity Post --only-nova-tests --resource-name=PostResource') ->assertSuccessful(); $this->assertFileDoesNotExist('app/Repositories/PostRepository.php'); From 1f250a242f2dffd6f3c302d5d004b16bc9d98edb Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Tue, 1 Jul 2025 17:28:11 +0300 Subject: [PATCH 07/17] style: fix --- src/Generators/NovaTestGenerator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index 64ab87d6..a2f2da9b 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -134,6 +134,7 @@ protected function doesNovaResourceExists(): bool foreach ($allNovaClasses as $class) { if (Str::contains($class, $this->novaResourceName)) { $this->fullNovaResourcePath = $class; + return true; } } @@ -144,12 +145,15 @@ protected function doesNovaResourceExists(): bool protected function getAllNovaClasses(string $directory): array { $classes = []; + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); foreach ($iterator as $file) { if ($file->isFile() && $file->getExtension() === 'php') { $relativePath = str_replace(app_path() . DIRECTORY_SEPARATOR, '', $file->getPathname()); + $class = 'App\\' . str_replace(['/', '.php'], ['\\', ''], $relativePath); + $classes[] = $class; } } From 5c49cecb86282ba2a24b334471a40ace03186008 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Wed, 2 Jul 2025 10:58:01 +0300 Subject: [PATCH 08/17] refactor: remove useless --- src/Generators/NovaTestGenerator.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index a2f2da9b..9126af1a 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -127,9 +127,7 @@ protected function isFixtureNeeded($type): bool protected function doesNovaResourceExists(): bool { - $novaDirectory = app_path('Nova'); - - $allNovaClasses = $this->getAllNovaClasses($novaDirectory); + $allNovaClasses = $this->getAllNovaClasses(); foreach ($allNovaClasses as $class) { if (Str::contains($class, $this->novaResourceName)) { @@ -142,11 +140,11 @@ protected function doesNovaResourceExists(): bool return false; } - protected function getAllNovaClasses(string $directory): array + protected function getAllNovaClasses(): array { $classes = []; - $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(app_path('Nova'))); foreach ($iterator as $file) { if ($file->isFile() && $file->getExtension() === 'php') { From a66d9ce796e22300ca2e7b86fe3377e6972e4a59 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Tue, 8 Jul 2025 13:35:32 +0300 Subject: [PATCH 09/17] fix:tests --- src/Commands/MakeEntityCommand.php | 15 +- src/Generators/EntityGenerator.php | 5 + src/Generators/NovaTestGenerator.php | 76 +++++++--- tests/NovaTestGeneratorTest.php | 143 ++++++++++++++---- tests/Support/Command/CommandMockTrait.php | 5 +- tests/Support/FileSystemMock.php | 13 ++ tests/Support/Nova/Resource.php | 8 + .../Resources/WelcomeBonusDraftResource.php | 58 +++++++ tests/Support/Nova/WelcomeBonusResource.php | 2 +- .../NovaTestGeneratorMockTrait.php | 7 + 10 files changed, 256 insertions(+), 76 deletions(-) create mode 100644 tests/Support/Nova/Resource.php create mode 100644 tests/Support/Nova/Resources/WelcomeBonusDraftResource.php diff --git a/src/Commands/MakeEntityCommand.php b/src/Commands/MakeEntityCommand.php index 466593ec..3da3a153 100644 --- a/src/Commands/MakeEntityCommand.php +++ b/src/Commands/MakeEntityCommand.php @@ -214,23 +214,12 @@ protected function generate() protected function runGeneration($generator) { - $resourceName = "{$this->argument('name')}Resource"; - - if (!empty($this->option('resource-name'))){ - $resourceName = $this->option('resource-name'); - } - - $generatorInstance = app($generator); - - if (method_exists($generatorInstance, 'setResource')) { - $generatorInstance->setResource($resourceName); - } - - $generatorInstance + app($generator) ->setModel($this->argument('name')) ->setFields($this->getFields()) ->setRelations($this->getRelations()) ->setCrudOptions($this->getCrudOptions()) + ->setMetaData(['resource_name' => $this->option('resource-name')]) ->generate(); } diff --git a/src/Generators/EntityGenerator.php b/src/Generators/EntityGenerator.php index e8dd2366..aed5228e 100644 --- a/src/Generators/EntityGenerator.php +++ b/src/Generators/EntityGenerator.php @@ -90,6 +90,11 @@ public function setRelations(RelationsDTO $relations) return $this; } + public function setMetaData(array $data): self + { + return $this; + } + public function __construct() { $this->paths = config('entity-generator.paths'); diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index 9126af1a..dc78753d 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -10,36 +10,48 @@ use RonasIT\Support\Exceptions\ClassNotExistsException; use RecursiveIteratorIterator; use RecursiveDirectoryIterator; +use RonasIT\Support\Exceptions\EntityCreateException; class NovaTestGenerator extends AbstractTestsGenerator { - protected string $novaResourceName; + protected string $resourceName; protected ?string $fullNovaResourcePath = null; + protected string $shortNovaResourceName; + + protected string $novaPath; + + public function __construct() + { + $this->novaPath = app_path('Nova'); + + parent::__construct(); + } + public function generate(): void { if (class_exists(NovaServiceProvider::class)) { if (!$this->doesNovaResourceExists()) { $this->throwFailureException( ClassNotExistsException::class, - "Cannot create Nova{$this->novaResourceName}Test cause {$this->novaResourceName} Nova resource does not exist.", - "Create {$this->novaResourceName} Nova resource." + "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", + "Create {$this->resourceName} Nova resource." ); } - if ($this->classExists('nova', "Nova{$this->novaResourceName}Test")) { + if ($this->classExists('nova', "Nova{$this->shortNovaResourceName}Test")) { $this->throwFailureException( ClassAlreadyExistsException::class, - "Cannot create Nova{$this->novaResourceName}Test cause it's already exist.", - "Remove Nova{$this->novaResourceName}Test." + "Cannot create Nova{$this->shortNovaResourceName}Test cause it's already exist.", + "Remove Nova{$this->resourceName}Test." ); } if (!$this->classExists('models', $this->model)) { $this->throwFailureException( ClassNotExistsException::class, - "Cannot create Nova{$this->novaResourceName}Test cause {$this->model} does not exist.", + "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->model} does not exist.", "Create a {$this->model} Model by himself or run command 'php artisan make:entity {$this->model} --only-model'." ); } @@ -50,9 +62,13 @@ public function generate(): void } } - public function setResource($novaResourceName) + public function setMetaData(array $data): self { - $this->novaResourceName = Str::studly($novaResourceName); + $resourceName = empty($data['resource_name']) ? "{$this->model}Resource" : $data['resource_name']; + + $this->resourceName = Str::studly($resourceName); + + $this->shortNovaResourceName = Str::afterLast($this->resourceName, '\\'); return $this; } @@ -77,9 +93,9 @@ public function generateTests(): void 'filters' => $filters, ]); - $this->saveClass('tests', "Nova{$this->novaResourceName}Test", $fileContent); + $this->saveClass('tests', "Nova{$this->shortNovaResourceName}Test", $fileContent); - event(new SuccessCreateMessage("Created a new Nova test: Nova{$this->novaResourceName}Test")); + event(new SuccessCreateMessage("Created a new Nova test: Nova{$this->shortNovaResourceName}Test")); } protected function getActions(): array @@ -117,7 +133,7 @@ protected function loadNovaFilters() public function getTestClassName(): string { - return "Nova{$this->novaResourceName}Test"; + return "Nova{$this->shortNovaResourceName}Test"; } protected function isFixtureNeeded($type): bool @@ -129,34 +145,44 @@ protected function doesNovaResourceExists(): bool { $allNovaClasses = $this->getAllNovaClasses(); + $resources = []; + foreach ($allNovaClasses as $class) { - if (Str::contains($class, $this->novaResourceName)) { - $this->fullNovaResourcePath = $class; + if ($class === $this->resourceName) { + $this->fullNovaResourcePath = "App\\Nova\\{$this->resourceName}"; return true; } + + if (Str::contains($class, $this->model) && is_subclass_of("App\\Nova\\{$class}", "App\\Nova\\Resource")) { + $resources[] = $class; + } + } + + if (count($resources) > 1) { + $resources = implode(', ', $resources); + + $this->throwFailureException( + EntityCreateException::class, + "Cannot create Nova{$this->shortNovaResourceName}Test cause I found a lot of suitable resources: $resources", + "Please, use --resource-name option" + ); } return false; } - protected function getAllNovaClasses(): array + protected function getAllNovaClasses(): \Generator { - $classes = []; - - $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(app_path('Nova'))); + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->novaPath)); foreach ($iterator as $file) { if ($file->isFile() && $file->getExtension() === 'php') { - $relativePath = str_replace(app_path() . DIRECTORY_SEPARATOR, '', $file->getPathname()); - - $class = 'App\\' . str_replace(['/', '.php'], ['\\', ''], $relativePath); + $relativePath = Str::after($file->getPathname(), $this->novaPath . DIRECTORY_SEPARATOR); - $classes[] = $class; + yield str_replace(['/', '.php'], ['\\', ''], $relativePath); } } - - return $classes; } protected function collectFilters(): array @@ -194,7 +220,7 @@ protected function getFiltersFromFields(): array protected function getFilters(): array { - $filters= []; + $filters = []; $novaResourceFilters = $this->loadNovaFilters(); foreach ($novaResourceFilters as $filter) { diff --git a/tests/NovaTestGeneratorTest.php b/tests/NovaTestGeneratorTest.php index 0ce297c2..4004acb1 100644 --- a/tests/NovaTestGeneratorTest.php +++ b/tests/NovaTestGeneratorTest.php @@ -11,6 +11,7 @@ use Laravel\Nova\NovaServiceProvider; use RonasIT\Support\Tests\Support\Models\WelcomeBonus; use Mockery; +use RonasIT\Support\Exceptions\EntityCreateException; class NovaTestGeneratorTest extends TestCase { @@ -33,12 +34,12 @@ public function testGenerateResourceNotExists() $this->assertExceptionThrew( className: ClassNotExistsException::class, - message: 'Cannot create NovaPostTest cause Post Nova resource does not exist. Create Post Nova resource.', + message: 'Cannot create NovaPostResourceTest cause PostResource Nova resource does not exist. Create PostResource Nova resource.', ); app(NovaTestGenerator::class) ->setModel('Post') - ->setResource('Post') + ->setMetaData(['resource_name' => 'PostResource']) ->generate(); } @@ -47,17 +48,17 @@ public function testGenerateNovaTestAlreadyExists() $this->mockNovaServiceProviderExists(); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaPostTest']), + $this->classExistsMethodCall(['nova', 'NovaPostResourceTest']), ]); $this->assertExceptionThrew( className: ClassAlreadyExistsException::class, - message: "Cannot create NovaPostTest cause it's already exist. Remove NovaPostTest.", + message: "Cannot create NovaPostResourceTest cause it's already exist. Remove NovaPostResourceTest.", ); app(NovaTestGenerator::class) ->setModel('Post') - ->setResource('Post') + ->setMetaData(['resource_name' => 'PostResource']) ->generate(); } @@ -74,7 +75,7 @@ public function testNovaTestStubNotExist() ); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusTest'], false), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), @@ -83,22 +84,18 @@ public function testNovaTestStubNotExist() $this->mockNovaRequestClassCall(); - $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); - $mock - ->shouldReceive('beginTransaction', 'rollBack') - ->once(); $this->mockDBTransactionStartRollback(); app(NovaTestGenerator::class) ->setModel('WelcomeBonus') - ->setResource('WelcomeBonus') + ->setMetaData(['resource_name' => 'WelcomeBonusResource']) ->generate(); $this->assertFileDoesNotExist('tests/NovaWelcomeBonusTest.php'); - $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusTest/nova_welcome_bonus_dump.sql'); - $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusTest/create_welcome_bonus_request.json'); - $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusTest/create_welcome_bonus_response.json'); - $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusTest/update_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusResourceTest/nova_welcome_bonus_dump.sql'); + $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_response.json'); + $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/update_welcome_bonus_request.json'); $this->assertEventPushed( className: WarningEvent::class, @@ -118,7 +115,7 @@ public function testDumpStubNotExist() ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusTest'], false), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), @@ -126,14 +123,14 @@ public function testDumpStubNotExist() app(NovaTestGenerator::class) ->setModel('WelcomeBonus') - ->setResource('WelcomeBonus') + ->setMetaData(['resource_name' => 'WelcomeBonusResource']) ->generate(); - $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusTest.php'); - $this->assertFileDoesNotExist('tests/fixtures/NovaWelcomeBonusTest/nova_welcome_bonus_dump.sql'); - $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusTest/create_welcome_bonus_request.json'); - $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusTest/create_welcome_bonus_response.json'); - $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusTest/update_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusResourceTest.php'); + $this->assertFileDoesNotExist('tests/fixtures/NovaWelcomeBonusResourceTest/nova_welcome_bonus_dump.sql'); + $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_response.json'); + $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/update_welcome_bonus_request.json'); $this->assertEventPushed( className: WarningEvent::class, @@ -148,17 +145,97 @@ public function testSuccess() ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusTest'], false), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), ]); - $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); - $mock - ->shouldReceive('beginTransaction', 'rollBack') - ->once(); + $this->mockDBTransactionStartRollback(); + + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), + ); + + $this->mockNovaRequestClassCall(); + + app(NovaTestGenerator::class) + ->setModel('WelcomeBonus') + ->setMetaData(['resource_name' => 'WelcomeBonusResource']) + ->generate(); + + $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusResourceTest.php'); + $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusResourceTest/nova_welcome_bonus_dump.sql'); + $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_response.json'); + $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/update_welcome_bonus_request.json'); + } + + public function testWithManySameResources() + { + $this->mockNovaServiceProviderExists(); + + $this->assertExceptionThrew( + className: EntityCreateException::class, + message: 'Cannot create NovaPostResourceTest cause I found a lot of suitable resources: Resources\PostResource Please, use --resource-name option', + ); + + app(NovaTestGenerator::class) + ->setModel('Post') + ->setMetaData(['resource_name' => 'PostResource']) + ->generate(); + } + + public function testSuccessWithoutSetMetaData() + { + config([ + 'entity-generator.paths.models' => 'RonasIT/Support/Tests/Support/Models', + ]); + + $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), + $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['models', 'User'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + ]); + + $this->mockDBTransactionStartRollback(); + + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), + ); + + $this->mockNovaRequestClassCall(); + + app(NovaTestGenerator::class) + ->setModel('WelcomeBonus') + ->setMetaData(['resource_name' => null]) + ->generate(); + + $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusResourceTest.php'); + $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusResourceTest/nova_welcome_bonus_dump.sql'); + $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_response.json'); + $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/update_welcome_bonus_request.json'); + } + + public function testSuccessWithNestedFile(): void + { + config([ + 'entity-generator.paths.models' => 'RonasIT/Support/Tests/Support/Models', + ]); + + $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusDraftResourceTest'], false), + $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['models', 'User'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + ]); $this->mockDBTransactionStartRollback(); @@ -171,14 +248,14 @@ public function testSuccess() app(NovaTestGenerator::class) ->setModel('WelcomeBonus') - ->setResource('WelcomeBonus') + ->setMetaData(['resource_name' => 'Resources\WelcomeBonusDraftResource']) ->generate(); - $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusTest.php'); - $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusTest/nova_welcome_bonus_dump.sql'); - $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusTest/create_welcome_bonus_request.json'); - $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusTest/create_welcome_bonus_response.json'); - $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusTest/update_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusDraftResourceTest.php'); + $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusDraftResourceTest/nova_welcome_bonus_dump.sql'); + $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusDraftResourceTest/create_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusDraftResourceTest/create_welcome_bonus_response.json'); + $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusDraftResourceTest/update_welcome_bonus_request.json'); } public function testGenerateNovaPackageNotInstall() diff --git a/tests/Support/Command/CommandMockTrait.php b/tests/Support/Command/CommandMockTrait.php index bd2881a1..738c80da 100644 --- a/tests/Support/Command/CommandMockTrait.php +++ b/tests/Support/Command/CommandMockTrait.php @@ -89,10 +89,7 @@ public function mockGeneratorOnlyNovaTests(): void $this->classExistsMethodCall(['factories', 'PostFactory']), ]); - $mock = Mockery::mock('alias:Illuminate\Support\Facades\DB'); - $mock - ->shouldReceive('beginTransaction', 'rollBack') - ->once(); + $this->mockDBTransactionStartRollback(); $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall(['Laravel\Nova\NovaServiceProvider', true]), diff --git a/tests/Support/FileSystemMock.php b/tests/Support/FileSystemMock.php index 11c84f27..425cbf5d 100644 --- a/tests/Support/FileSystemMock.php +++ b/tests/Support/FileSystemMock.php @@ -8,6 +8,7 @@ class FileSystemMock { public ?array $novaModels = null; + public ?array $novaResources = null; public ?array $novaActions = null; public ?array $models = null; public ?array $controllers = null; @@ -32,6 +33,18 @@ public function setStructure(): void } } + if (!is_null($this->novaResources)) { + if (!array_key_exists('Nova', $structure['app'])) { + $structure['app']['Nova'] = []; + } + + $structure['app']['Nova']['Resources'] = []; + + foreach ($this->novaResources as $novaResource => $content) { + $structure['app']['Nova']['Resources'][$novaResource] = $content; + } + } + if (!is_null($this->novaActions)) { if (!array_key_exists('Nova', $structure['app'])) { $structure['app']['Nova'] = []; diff --git a/tests/Support/Nova/Resource.php b/tests/Support/Nova/Resource.php new file mode 100644 index 00000000..15bcf285 --- /dev/null +++ b/tests/Support/Nova/Resource.php @@ -0,0 +1,8 @@ +novaModels = [ 'WelcomeBonusResource.php' => $this->mockPhpFileContent(), + 'PostResource.php' => $this->mockPhpFileContent(), + ]; + + $fileSystemMock->novaResources = [ + 'WelcomeBonusDraftResource.php' => $this->mockPhpFileContent(), + 'PostResource.php' => $this->mockPhpFileContent(), ]; $fileSystemMock->models = [ 'WelcomeBonus.php' => $this->mockPhpFileContent(), + 'WelcomeBonusResource.php' => $this->mockPhpFileContent(), ]; $fileSystemMock->testFixtures = [ From c45d415da86d6dfdea4848e4801147ece266cdff Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Tue, 8 Jul 2025 16:24:00 +0300 Subject: [PATCH 10/17] refactor: check only nova resources --- src/Generators/NovaTestGenerator.php | 22 +++---- tests/NovaTestGeneratorTest.php | 46 ++++++++++----- tests/Support/Command/CommandMockTrait.php | 4 +- tests/Support/Models/Post.php | 25 ++++++++ tests/Support/Nova/Resources/PostResource.php | 59 +++++++++++++++++++ .../Resources/WelcomeBonusDraftResource.php | 3 +- .../NovaTestGeneratorMockTrait.php | 4 +- 7 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 tests/Support/Models/Post.php create mode 100644 tests/Support/Nova/Resources/PostResource.php diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index dc78753d..745ff722 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -32,6 +32,14 @@ public function __construct() public function generate(): void { if (class_exists(NovaServiceProvider::class)) { + if (!$this->classExists('models', $this->model)) { + $this->throwFailureException( + ClassNotExistsException::class, + "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->model} does not exist.", + "Create a {$this->model} Model by himself or run command 'php artisan make:entity {$this->model} --only-model'." + ); + } + if (!$this->doesNovaResourceExists()) { $this->throwFailureException( ClassNotExistsException::class, @@ -44,15 +52,7 @@ public function generate(): void $this->throwFailureException( ClassAlreadyExistsException::class, "Cannot create Nova{$this->shortNovaResourceName}Test cause it's already exist.", - "Remove Nova{$this->resourceName}Test." - ); - } - - if (!$this->classExists('models', $this->model)) { - $this->throwFailureException( - ClassNotExistsException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->model} does not exist.", - "Create a {$this->model} Model by himself or run command 'php artisan make:entity {$this->model} --only-model'." + "Remove Nova{$this->shortNovaResourceName}Test." ); } @@ -159,12 +159,12 @@ protected function doesNovaResourceExists(): bool } } - if (count($resources) > 1) { + if (!empty($resources)) { $resources = implode(', ', $resources); $this->throwFailureException( EntityCreateException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause I found a lot of suitable resources: $resources", + "Cannot create Nova{$this->shortNovaResourceName}Test cause I am found a lot of suitable resources: $resources", "Please, use --resource-name option" ); } diff --git a/tests/NovaTestGeneratorTest.php b/tests/NovaTestGeneratorTest.php index 4004acb1..cd42a184 100644 --- a/tests/NovaTestGeneratorTest.php +++ b/tests/NovaTestGeneratorTest.php @@ -10,7 +10,6 @@ use RonasIT\Support\Tests\Support\NovaTestGeneratorTest\NovaTestGeneratorMockTrait; use Laravel\Nova\NovaServiceProvider; use RonasIT\Support\Tests\Support\Models\WelcomeBonus; -use Mockery; use RonasIT\Support\Exceptions\EntityCreateException; class NovaTestGeneratorTest extends TestCase @@ -29,17 +28,17 @@ public function testGenerateResourceNotExists() $this->mockNovaServiceProviderExists(); $this->mockClass(NovaTestGenerator::class, [ - $this->doesNovaResourceExistsCall(false), + $this->classExistsMethodCall(['models', 'News']), ]); $this->assertExceptionThrew( className: ClassNotExistsException::class, - message: 'Cannot create NovaPostResourceTest cause PostResource Nova resource does not exist. Create PostResource Nova resource.', + message: 'Cannot create NovaNewsResourceTest cause NewsResource Nova resource does not exist. Create NewsResource Nova resource.', ); app(NovaTestGenerator::class) - ->setModel('Post') - ->setMetaData(['resource_name' => 'PostResource']) + ->setModel('News') + ->setMetaData(['resource_name' => 'NewsResource']) ->generate(); } @@ -48,6 +47,7 @@ public function testGenerateNovaTestAlreadyExists() $this->mockNovaServiceProviderExists(); $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['models', 'Post']), $this->classExistsMethodCall(['nova', 'NovaPostResourceTest']), ]); @@ -58,7 +58,7 @@ className: ClassAlreadyExistsException::class, app(NovaTestGenerator::class) ->setModel('Post') - ->setMetaData(['resource_name' => 'PostResource']) + ->setMetaData(['resource_name' => 'Resources\PostResource']) ->generate(); } @@ -75,8 +75,8 @@ public function testNovaTestStubNotExist() ); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), @@ -115,8 +115,8 @@ public function testDumpStubNotExist() ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), ]); @@ -145,8 +145,8 @@ public function testSuccess() ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), @@ -175,16 +175,18 @@ public function testSuccess() public function testWithManySameResources() { - $this->mockNovaServiceProviderExists(); + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + ); $this->assertExceptionThrew( className: EntityCreateException::class, - message: 'Cannot create NovaPostResourceTest cause I found a lot of suitable resources: Resources\PostResource Please, use --resource-name option', + message: 'Cannot create NovaPostResourceTest cause I am found a lot of suitable resources: Resources\PostResource Please, use --resource-name option', ); app(NovaTestGenerator::class) ->setModel('Post') - ->setMetaData(['resource_name' => 'PostResource']) + ->setMetaData(['resource_name' => null]) ->generate(); } @@ -195,8 +197,8 @@ public function testSuccessWithoutSetMetaData() ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), @@ -230,8 +232,8 @@ public function testSuccessWithNestedFile(): void ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusDraftResourceTest'], false), $this->classExistsMethodCall(['models', 'WelcomeBonus']), + $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusDraftResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), @@ -258,6 +260,22 @@ public function testSuccessWithNestedFile(): void $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusDraftResourceTest/update_welcome_bonus_request.json'); } + public function testSetIncorrectModel(): void + { + $this->mockNovaServiceProviderExists(); + + $this->assertExceptionThrew( + className: ClassNotExistsException::class, + message: "Cannot create NovaSomeUndefinedModelResourceTest cause SomeUndefinedModel does not exist. " + . "Create a SomeUndefinedModel Model by himself or run command 'php artisan make:entity SomeUndefinedModel --only-model'.", + ); + + app(NovaTestGenerator::class) + ->setModel('SomeUndefinedModel') + ->setMetaData(['resource_name' => null]) + ->generate(); + } + public function testGenerateNovaPackageNotInstall() { $this->mockNovaServiceProviderExists(false); diff --git a/tests/Support/Command/CommandMockTrait.php b/tests/Support/Command/CommandMockTrait.php index 738c80da..7fe38067 100644 --- a/tests/Support/Command/CommandMockTrait.php +++ b/tests/Support/Command/CommandMockTrait.php @@ -5,7 +5,6 @@ use RonasIT\Support\Generators\NovaTestGenerator; use RonasIT\Support\Tests\Support\FileSystemMock; use RonasIT\Support\Tests\Support\GeneratorMockTrait; -use Mockery; trait CommandMockTrait { @@ -67,6 +66,7 @@ public function mockGenerator(): void $this->nativeClassExistsMethodCall(['RonasIT\Support\Tests\Support\Command\Models\Post', true]), ); } + public function mockGeneratorOnlyNovaTests(): void { $this->mockClass(NovaTestGenerator::class, [ @@ -82,8 +82,8 @@ public function mockGeneratorOnlyNovaTests(): void name: 'loadNovaFilters', result: [], ), - $this->classExistsMethodCall(['nova', 'NovaPostResourceTest'], false), $this->classExistsMethodCall(['models', 'Post']), + $this->classExistsMethodCall(['nova', 'NovaPostResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), $this->classExistsMethodCall(['factories', 'PostFactory']), $this->classExistsMethodCall(['factories', 'PostFactory']), diff --git a/tests/Support/Models/Post.php b/tests/Support/Models/Post.php new file mode 100644 index 00000000..5273b878 --- /dev/null +++ b/tests/Support/Models/Post.php @@ -0,0 +1,25 @@ +novaModels = [ 'WelcomeBonusResource.php' => $this->mockPhpFileContent(), - 'PostResource.php' => $this->mockPhpFileContent(), ]; $fileSystemMock->novaResources = [ @@ -40,7 +39,8 @@ public function mockFilesystem(): void $fileSystemMock->models = [ 'WelcomeBonus.php' => $this->mockPhpFileContent(), - 'WelcomeBonusResource.php' => $this->mockPhpFileContent(), + 'Post.php' => $this->mockPhpFileContent(), + 'News.php' => $this->mockPhpFileContent(), ]; $fileSystemMock->testFixtures = [ From 0fa88db85fb19e7751a94dffe482b13ae8aff625 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Tue, 8 Jul 2025 16:26:18 +0300 Subject: [PATCH 11/17] refactor: change isNovaResourceExists method --- src/Generators/NovaTestGenerator.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index 745ff722..674d35cb 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -40,13 +40,7 @@ public function generate(): void ); } - if (!$this->doesNovaResourceExists()) { - $this->throwFailureException( - ClassNotExistsException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", - "Create {$this->resourceName} Nova resource." - ); - } + $this->isNovaResourceExists(); if ($this->classExists('nova', "Nova{$this->shortNovaResourceName}Test")) { $this->throwFailureException( @@ -141,7 +135,7 @@ protected function isFixtureNeeded($type): bool return true; } - protected function doesNovaResourceExists(): bool + protected function isNovaResourceExists(): true { $allNovaClasses = $this->getAllNovaClasses(); @@ -169,7 +163,11 @@ protected function doesNovaResourceExists(): bool ); } - return false; + $this->throwFailureException( + ClassNotExistsException::class, + "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", + "Create {$this->resourceName} Nova resource." + ); } protected function getAllNovaClasses(): \Generator From 47aed4fbb1bb99b3178ed5cfe64268c2d5343400 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Wed, 9 Jul 2025 13:43:30 +0300 Subject: [PATCH 12/17] fix: remove useless --- tests/Support/GeneratorMockTrait.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/Support/GeneratorMockTrait.php b/tests/Support/GeneratorMockTrait.php index 86834f1e..33cec554 100644 --- a/tests/Support/GeneratorMockTrait.php +++ b/tests/Support/GeneratorMockTrait.php @@ -41,15 +41,6 @@ public function classExistsMethodCall(array $arguments, bool $result = true): ar ]; } - public function doesNovaResourceExistsCall(bool $result = true): array - { - return [ - 'function' => 'doesNovaResourceExists', - 'arguments' => [], - 'result' => $result - ]; - } - public function nativeClassExistsMethodCall(array $arguments, bool $result = true): array { return [ From bf4bfc9091d67d78073ee532f9ba2c9dcac47fb5 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Wed, 9 Jul 2025 13:47:00 +0300 Subject: [PATCH 13/17] style: import generator --- src/Generators/NovaTestGenerator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index 674d35cb..25e97701 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -11,6 +11,7 @@ use RecursiveIteratorIterator; use RecursiveDirectoryIterator; use RonasIT\Support\Exceptions\EntityCreateException; +use Generator; class NovaTestGenerator extends AbstractTestsGenerator { @@ -170,7 +171,7 @@ protected function isNovaResourceExists(): true ); } - protected function getAllNovaClasses(): \Generator + protected function getAllNovaClasses(): Generator { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->novaPath)); From fd12be453b376911b448798f1ddd6fc22ded7f68 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Wed, 9 Jul 2025 14:39:38 +0300 Subject: [PATCH 14/17] chore:update readme --- ReadMe.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ReadMe.md b/ReadMe.md index ba443670..9b22c8b8 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -123,6 +123,14 @@ Syntax: --only-resource : Set this flag if you want to create only resource. + --only-nova-resource : Set this flag if you want to create only nova resource. + + --only-nova-tests : Set this flag if you want to create only nova resource tests. + + --resource-name[=RESOURCE-NAME] : Override the default (App\\Nova\\ModelResource) Nova resource name. Used only with --only-nova-tests. + + please, use flag variable with double screening and double quotes without Nova directory, for example --resource-name="Resources\\Banner\\BannerResource" + #### Mode combination options --only-entity : Generate stack of classes to work with entity inside the app (Migration/Model/Service/Repository) From a6a2747debbe1c9eaa7b44e39861c5310728fc7e Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Fri, 11 Jul 2025 14:26:28 +0300 Subject: [PATCH 15/17] refactor:use common resources --- composer.json | 3 +- src/Generators/NovaTestGenerator.php | 92 +++--- stubs/nova_resource.blade.php | 1 + tests/CommandTest.php | 2 + tests/NovaTestGeneratorTest.php | 64 +++-- tests/Support/Command/CommandMockTrait.php | 2 + tests/Support/Models/News.php | 25 ++ tests/Support/Nova/PostResource.php | 59 ++++ tests/Support/Nova/Resources/PostResource.php | 2 +- tests/Support/Nova/Resources/WelcomeBonus.php | 59 ++++ .../Resources/WelcomeBonusDraftResource.php | 2 +- tests/Support/Nova/WelcomeBonusResource.php | 1 + .../{Nova => NovaResource}/Resource.php | 2 +- .../NovaTestGeneratorMockTrait.php | 1 + tests/fixtures/CommandTest/nova_resource.php | 1 + .../created_resource.php | 1 + ...d_resource_without_command_line_fields.php | 1 + .../create_post_request.json | 4 + .../create_post_response.json | 5 + .../created_post_resource_test.php | 261 ++++++++++++++++++ .../NovaTestGeneratorTest/post_dump.sql | 3 + .../update_post_request.json | 4 + 22 files changed, 533 insertions(+), 62 deletions(-) create mode 100644 tests/Support/Models/News.php create mode 100644 tests/Support/Nova/PostResource.php create mode 100644 tests/Support/Nova/Resources/WelcomeBonus.php rename tests/Support/{Nova => NovaResource}/Resource.php (52%) create mode 100644 tests/fixtures/NovaTestGeneratorTest/create_post_request.json create mode 100644 tests/fixtures/NovaTestGeneratorTest/create_post_response.json create mode 100644 tests/fixtures/NovaTestGeneratorTest/created_post_resource_test.php create mode 100644 tests/fixtures/NovaTestGeneratorTest/post_dump.sql create mode 100644 tests/fixtures/NovaTestGeneratorTest/update_post_request.json diff --git a/composer.json b/composer.json index 825c5857..8053b2aa 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,8 @@ "psr-4": { "RonasIT\\Support\\Tests\\": "tests/", "RonasIT\\Support\\Tests\\Support\\": "tests/Support/", - "App\\Nova\\": "tests/Support/Nova/" + "App\\Nova\\": "tests/Support/Nova/", + "Laravel\\Nova\\": "tests/Support/NovaResource" }, "files": [ "tests/TestCase.php" diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index 25e97701..b009b9ce 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -15,11 +15,11 @@ class NovaTestGenerator extends AbstractTestsGenerator { - protected string $resourceName; + protected ?string $resourceName; protected ?string $fullNovaResourcePath = null; - protected string $shortNovaResourceName; + protected ?string $shortNovaResourceName; protected string $novaPath; @@ -36,7 +36,7 @@ public function generate(): void if (!$this->classExists('models', $this->model)) { $this->throwFailureException( ClassNotExistsException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->model} does not exist.", + "Cannot create Nova{$this->model}Resource Test cause {$this->model} does not exist.", "Create a {$this->model} Model by himself or run command 'php artisan make:entity {$this->model} --only-model'." ); } @@ -59,11 +59,7 @@ public function generate(): void public function setMetaData(array $data): self { - $resourceName = empty($data['resource_name']) ? "{$this->model}Resource" : $data['resource_name']; - - $this->resourceName = Str::studly($resourceName); - - $this->shortNovaResourceName = Str::afterLast($this->resourceName, '\\'); + $this->resourceName = !empty($data['resource_name']) ? Str::studly($data['resource_name']) : null; return $this; } @@ -136,42 +132,44 @@ protected function isFixtureNeeded($type): bool return true; } - protected function isNovaResourceExists(): true + protected function isNovaResourceExists(): void { - $allNovaClasses = $this->getAllNovaClasses(); + $resource = $this->getNovaResource(); - $resources = []; + $this->shortNovaResourceName = Str::afterLast($resource, '\\'); + $this->fullNovaResourcePath = "App\\Nova\\{$resource}"; - foreach ($allNovaClasses as $class) { - if ($class === $this->resourceName) { - $this->fullNovaResourcePath = "App\\Nova\\{$this->resourceName}"; + if (!class_exists($this->fullNovaResourcePath)) { + $this->throwFailureException( + ClassNotExistsException::class, + "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", + "Create {$this->resourceName} Nova resource." + ); + } + } - return true; - } + protected function getNovaResource(): ?string + { + if (!empty($this->resourceName)) { + return $this->resourceName; + } else { + $commonResources = $this->getCommonNovaResources(); - if (Str::contains($class, $this->model) && is_subclass_of("App\\Nova\\{$class}", "App\\Nova\\Resource")) { - $resources[] = $class; - } - } + if (count($commonResources) > 1) { + $commonResources = implode(', ', $commonResources); - if (!empty($resources)) { - $resources = implode(', ', $resources); + $this->throwFailureException( + EntityCreateException::class, + "Cannot create Nova{$this->model}Resource Test cause was found a lot of suitable resources: $commonResources", + "Please, use --resource-name option" + ); + } - $this->throwFailureException( - EntityCreateException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause I am found a lot of suitable resources: $resources", - "Please, use --resource-name option" - ); + return $commonResources[0]; } - - $this->throwFailureException( - ClassNotExistsException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", - "Create {$this->resourceName} Nova resource." - ); } - protected function getAllNovaClasses(): Generator + protected function allCommonNovaResources(): Generator { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->novaPath)); @@ -179,11 +177,35 @@ protected function getAllNovaClasses(): Generator if ($file->isFile() && $file->getExtension() === 'php') { $relativePath = Str::after($file->getPathname(), $this->novaPath . DIRECTORY_SEPARATOR); - yield str_replace(['/', '.php'], ['\\', ''], $relativePath); + $class = str_replace(['/', '.php'], ['\\', ''], $relativePath); + + if($this->isValidCommonResourceCheck($class)){ + yield $class; + } } } } + protected function getCommonNovaResources(): array + { + $commonNovaResources = $this->allCommonNovaResources(); + + $resources = []; + + foreach ($commonNovaResources as $resource) { + $resources[] = $resource; + } + + return $resources; + } + + protected function isValidCommonResourceCheck(string $resource) + { + $isContainModel = Str::afterLast(str_replace('Resource', '', $resource), '\\') === $this->model; + + return is_subclass_of("App\\Nova\\{$resource}", "Laravel\\Nova\\Resource") && $isContainModel; + } + protected function collectFilters(): array { $filtersFromFields = $this->getFiltersFromFields(); diff --git a/stubs/nova_resource.blade.php b/stubs/nova_resource.blade.php index 760d5af9..c51e3512 100644 --- a/stubs/nova_resource.blade.php +++ b/stubs/nova_resource.blade.php @@ -6,6 +6,7 @@ @foreach($types as $fieldType) use Laravel\Nova\Fields\{{$fieldType}}; @endforeach +use Laravel\Nova\Resource; class {{$model}}Resource extends Resource { diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 7502a507..f60804db 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -8,6 +8,7 @@ use RonasIT\Support\Tests\Support\Command\CommandMockTrait; use RonasIT\Support\Tests\Support\Command\Models\Post; use UnexpectedValueException; +use App\Nova\PostResource; class CommandTest extends TestCase { @@ -51,6 +52,7 @@ public function testCallCommand() $this->mockGenerator(); $this->mockGettingModelInstance(new Post()); + $this->app->instance(PostResource::class, new PostResource()); $this->mockDBTransactionStartRollback(2); $this diff --git a/tests/NovaTestGeneratorTest.php b/tests/NovaTestGeneratorTest.php index cd42a184..af06d88a 100644 --- a/tests/NovaTestGeneratorTest.php +++ b/tests/NovaTestGeneratorTest.php @@ -11,6 +11,7 @@ use Laravel\Nova\NovaServiceProvider; use RonasIT\Support\Tests\Support\Models\WelcomeBonus; use RonasIT\Support\Exceptions\EntityCreateException; +use RonasIT\Support\Tests\Support\Models\Post; class NovaTestGeneratorTest extends TestCase { @@ -25,12 +26,15 @@ public function setUp(): void public function testGenerateResourceNotExists() { - $this->mockNovaServiceProviderExists(); - $this->mockClass(NovaTestGenerator::class, [ $this->classExistsMethodCall(['models', 'News']), ]); + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall(["App\Nova\NewsResource"], false), + ); + $this->assertExceptionThrew( className: ClassNotExistsException::class, message: 'Cannot create NovaNewsResourceTest cause NewsResource Nova resource does not exist. Create NewsResource Nova resource.', @@ -44,13 +48,16 @@ className: ClassNotExistsException::class, public function testGenerateNovaTestAlreadyExists() { - $this->mockNovaServiceProviderExists(); - $this->mockClass(NovaTestGenerator::class, [ $this->classExistsMethodCall(['models', 'Post']), $this->classExistsMethodCall(['nova', 'NovaPostResourceTest']), ]); + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall(["App\Nova\Resources\PostResource"]), + ); + $this->assertExceptionThrew( className: ClassAlreadyExistsException::class, message: "Cannot create NovaPostResourceTest cause it's already exist. Remove NovaPostResourceTest.", @@ -71,6 +78,7 @@ public function testNovaTestStubNotExist() $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall(["App\Nova\WelcomeBonusResource"]), $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), ); @@ -105,8 +113,6 @@ className: WarningEvent::class, public function testDumpStubNotExist() { - $this->mockNovaServiceProviderExists(); - $this->mockNovaRequestClassCall(); config([ @@ -121,6 +127,11 @@ public function testDumpStubNotExist() $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), ]); + $this->mockNativeGeneratorFunctions( + $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall(["App\Nova\WelcomeBonusResource"]), + ); + app(NovaTestGenerator::class) ->setModel('WelcomeBonus') ->setMetaData(['resource_name' => 'WelcomeBonusResource']) @@ -156,6 +167,7 @@ public function testSuccess() $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall(["App\Nova\WelcomeBonusResource"]), $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), ); @@ -175,17 +187,21 @@ public function testSuccess() public function testWithManySameResources() { - $this->mockNativeGeneratorFunctions( - $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), - ); + $this->mockNovaServiceProviderExists(); + + $this->mockNovaRequestClassCall(); + + $this->mockClass(NovaTestGenerator::class, [ + $this->classExistsMethodCall(['models', 'WelcomeBonus']), + ]); $this->assertExceptionThrew( className: EntityCreateException::class, - message: 'Cannot create NovaPostResourceTest cause I am found a lot of suitable resources: Resources\PostResource Please, use --resource-name option', + message: 'Cannot create NovaWelcomeBonusResource Test cause was found a lot of suitable resources: WelcomeBonusResource, Resources\WelcomeBonus Please, use --resource-name option', ); app(NovaTestGenerator::class) - ->setModel('Post') + ->setModel('WelcomeBonus') ->setMetaData(['resource_name' => null]) ->generate(); } @@ -197,32 +213,33 @@ public function testSuccessWithoutSetMetaData() ]); $this->mockClass(NovaTestGenerator::class, [ - $this->classExistsMethodCall(['models', 'WelcomeBonus']), - $this->classExistsMethodCall(['nova', 'NovaWelcomeBonusResourceTest'], false), + $this->classExistsMethodCall(['models', 'Post']), + $this->classExistsMethodCall(['nova', 'NovaPostResourceTest'], false), $this->classExistsMethodCall(['models', 'User'], false), - $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), - $this->classExistsMethodCall(['factories', 'WelcomeBonusFactory'], false), + $this->classExistsMethodCall(['factories', 'PostFactory'], false), + $this->classExistsMethodCall(['factories', 'PostFactory'], false), ]); $this->mockDBTransactionStartRollback(); $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), - $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), + $this->nativeClassExistsMethodCall(["App\Nova\Resources\PostResource"]), + $this->nativeClassExistsMethodCall([Post::class, true]), ); $this->mockNovaRequestClassCall(); app(NovaTestGenerator::class) - ->setModel('WelcomeBonus') + ->setModel('Post') ->setMetaData(['resource_name' => null]) ->generate(); - $this->assertGeneratedFileEquals('created_resource_test.php', 'tests/NovaWelcomeBonusResourceTest.php'); - $this->assertGeneratedFileEquals('dump.sql', 'tests/fixtures/NovaWelcomeBonusResourceTest/nova_welcome_bonus_dump.sql'); - $this->assertGeneratedFileEquals('create_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_request.json'); - $this->assertGeneratedFileEquals('create_welcome_bonus_response.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/create_welcome_bonus_response.json'); - $this->assertGeneratedFileEquals('update_welcome_bonus_request.json', 'tests/fixtures/NovaWelcomeBonusResourceTest/update_welcome_bonus_request.json'); + $this->assertGeneratedFileEquals('created_post_resource_test.php', 'tests/NovaPostResourceTest.php'); + $this->assertGeneratedFileEquals('post_dump.sql', 'tests/fixtures/NovaPostResourceTest/nova_post_dump.sql'); + $this->assertGeneratedFileEquals('create_post_request.json', 'tests/fixtures/NovaPostResourceTest/create_post_request.json'); + $this->assertGeneratedFileEquals('create_post_response.json', 'tests/fixtures/NovaPostResourceTest/create_post_response.json'); + $this->assertGeneratedFileEquals('update_post_request.json', 'tests/fixtures/NovaPostResourceTest/update_post_request.json'); } public function testSuccessWithNestedFile(): void @@ -243,6 +260,7 @@ public function testSuccessWithNestedFile(): void $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall([NovaServiceProvider::class, true]), + $this->nativeClassExistsMethodCall(['App\Nova\Resources\WelcomeBonusDraftResource']), $this->nativeClassExistsMethodCall([WelcomeBonus::class, true]), ); @@ -266,7 +284,7 @@ public function testSetIncorrectModel(): void $this->assertExceptionThrew( className: ClassNotExistsException::class, - message: "Cannot create NovaSomeUndefinedModelResourceTest cause SomeUndefinedModel does not exist. " + message: "Cannot create NovaSomeUndefinedModelResource Test cause SomeUndefinedModel does not exist. " . "Create a SomeUndefinedModel Model by himself or run command 'php artisan make:entity SomeUndefinedModel --only-model'.", ); diff --git a/tests/Support/Command/CommandMockTrait.php b/tests/Support/Command/CommandMockTrait.php index 7fe38067..e7ab624a 100644 --- a/tests/Support/Command/CommandMockTrait.php +++ b/tests/Support/Command/CommandMockTrait.php @@ -63,6 +63,7 @@ public function mockGenerator(): void $this->nativeClassExistsMethodCall(['RonasIT\Support\Tests\Support\Command\Models\Post', true]), $this->nativeClassExistsMethodCall(['Laravel\Nova\NovaServiceProvider', true]), $this->nativeClassExistsMethodCall(['Laravel\Nova\NovaServiceProvider', true]), + $this->nativeClassExistsMethodCall(['App\Nova\PostResource']), $this->nativeClassExistsMethodCall(['RonasIT\Support\Tests\Support\Command\Models\Post', true]), ); } @@ -93,6 +94,7 @@ public function mockGeneratorOnlyNovaTests(): void $this->mockNativeGeneratorFunctions( $this->nativeClassExistsMethodCall(['Laravel\Nova\NovaServiceProvider', true]), + $this->nativeClassExistsMethodCall(['App\Nova\PostResource']), $this->nativeClassExistsMethodCall(['RonasIT\Support\Tests\Support\Command\Models\Post', true]), ); } diff --git a/tests/Support/Models/News.php b/tests/Support/Models/News.php new file mode 100644 index 00000000..e1c6c5ac --- /dev/null +++ b/tests/Support/Models/News.php @@ -0,0 +1,25 @@ +novaResources = [ 'WelcomeBonusDraftResource.php' => $this->mockPhpFileContent(), + 'WelcomeBonus.php' => $this->mockPhpFileContent(), 'PostResource.php' => $this->mockPhpFileContent(), ]; diff --git a/tests/fixtures/CommandTest/nova_resource.php b/tests/fixtures/CommandTest/nova_resource.php index b653b10b..a43b5419 100644 --- a/tests/fixtures/CommandTest/nova_resource.php +++ b/tests/fixtures/CommandTest/nova_resource.php @@ -6,6 +6,7 @@ use Illuminate\Http\Request; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Text; +use Laravel\Nova\Resource; class PostResource extends Resource { diff --git a/tests/fixtures/NovaResourceGeneratorTest/created_resource.php b/tests/fixtures/NovaResourceGeneratorTest/created_resource.php index 742c6158..f0de6419 100644 --- a/tests/fixtures/NovaResourceGeneratorTest/created_resource.php +++ b/tests/fixtures/NovaResourceGeneratorTest/created_resource.php @@ -7,6 +7,7 @@ use Laravel\Nova\Fields\Boolean; use Laravel\Nova\Fields\Text; use Laravel\Nova\Fields\ID; +use Laravel\Nova\Resource; class PostResource extends Resource { diff --git a/tests/fixtures/NovaResourceGeneratorTest/created_resource_without_command_line_fields.php b/tests/fixtures/NovaResourceGeneratorTest/created_resource_without_command_line_fields.php index 9d3f57e1..7ae28fb4 100644 --- a/tests/fixtures/NovaResourceGeneratorTest/created_resource_without_command_line_fields.php +++ b/tests/fixtures/NovaResourceGeneratorTest/created_resource_without_command_line_fields.php @@ -6,6 +6,7 @@ use Illuminate\Http\Request; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Text; +use Laravel\Nova\Resource; class PostResource extends Resource { diff --git a/tests/fixtures/NovaTestGeneratorTest/create_post_request.json b/tests/fixtures/NovaTestGeneratorTest/create_post_request.json new file mode 100644 index 00000000..538b482c --- /dev/null +++ b/tests/fixtures/NovaTestGeneratorTest/create_post_request.json @@ -0,0 +1,4 @@ +{ + "title": 1, + "name": 1 +} \ No newline at end of file diff --git a/tests/fixtures/NovaTestGeneratorTest/create_post_response.json b/tests/fixtures/NovaTestGeneratorTest/create_post_response.json new file mode 100644 index 00000000..ea1ee8ea --- /dev/null +++ b/tests/fixtures/NovaTestGeneratorTest/create_post_response.json @@ -0,0 +1,5 @@ +{ + "id": 1, + "title": 1, + "name": 1 +} \ No newline at end of file diff --git a/tests/fixtures/NovaTestGeneratorTest/created_post_resource_test.php b/tests/fixtures/NovaTestGeneratorTest/created_post_resource_test.php new file mode 100644 index 00000000..c3ce5c8d --- /dev/null +++ b/tests/fixtures/NovaTestGeneratorTest/created_post_resource_test.php @@ -0,0 +1,261 @@ +skipDocumentationCollecting(); + } + + public function testCreate(): void + { + $data = $this->getJsonFixture('create_post_request'); + + $response = $this->novaActingAs(self::$user)->novaCreateResourceAPICall(Post::class, $data); + + $response->assertCreated(); + + $this->assertEqualsFixture('create_post_response', $response->json()); + + // TODO: Need to remove last argument after first successful start + self::$postState->assertChangesEqualsFixture('create_posts_state', true); + } + + public function testCreateNoAuth(): void + { + $response = $this->novaCreateResourceAPICall(Post::class); + + $response->assertUnauthorized(); + + self::$postState->assertNotChanged(); + } + + public function testCreateValidationError(): void + { + $response = $this->novaActingAs(self::$user)->novaCreateResourceAPICall(Post::class); + + $response->assertUnprocessable(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture('create_validation_response', $response->json(), true); + + self::$postState->assertNotChanged(); + } + + public function testUpdate(): void + { + $data = $this->getJsonFixture('update_post_request'); + + $response = $this->novaActingAs(self::$user)->novaUpdateResourceAPICall(Post::class, 1, $data); + + $response->assertNoContent(); + + // TODO: Need to remove last argument after first successful start + self::$postState->assertChangesEqualsFixture('update_posts_state', true); + } + + public function testUpdateNotExists(): void + { + $data = $this->getJsonFixture('update_post_request'); + + $response = $this->novaActingAs(self::$user)->novaUpdateResourceAPICall(Post::class, 0, $data); + + $response->assertNotFound(); + } + + public function testUpdateNoAuth(): void + { + $response = $this->novaUpdateResourceAPICall(Post::class, 1); + + $response->assertUnauthorized(); + } + + public function testUpdateValidationError(): void + { + $response = $this->novaActingAs(self::$user)->novaUpdateResourceAPICall(Post::class, 4); + + $response->assertUnprocessable(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture('update_validation_response', $response->json(), true); + } + + public function testGetUpdatableFields(): void + { + $response = $this->novaActingAs(self::$user)->novaGetUpdatableFieldsAPICall(Post::class, 1); + + $response->assertOk(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture('get_updatable_fields_response', $response->json(), true); + } + + public function testDelete(): void + { + $response = $this->novaActingAs(self::$user)->novaDeleteResourceAPICall(Post::class, [1, 2]); + + $response->assertOk(); + + // TODO: Need to remove last argument after first successful start + self::$postState->assertChangesEqualsFixture('delete_posts_state', true); + } + + public function testDeleteNotExists(): void + { + $response = $this->novaActingAs(self::$user)->novaDeleteResourceAPICall(Post::class, [0]); + + $response->assertNotFound(); + } + + public function testDeleteNoAuth(): void + { + $response = $this->novaDeleteResourceAPICall(Post::class, [1, 2]); + + $response->assertUnauthorized(); + } + + public function testGet(): void + { + $response = $this->novaActingAs(self::$user)->novaGetResourceAPICall(Post::class, 1); + + $response->assertOk(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture('get_post_response', $response->json(), true); + } + + public function testGetNotExists(): void + { + $response = $this->novaActingAs(self::$user)->novaGetResourceAPICall(Post::class, 0); + + $response->assertNotFound(); + } + + public function testGetNoAuth(): void + { + $response = $this->novaGetResourceAPICall(Post::class, 1); + + $response->assertUnauthorized(); + } + + public function testSearchUnauthorized(): void + { + $response = $this->novaSearchResourceAPICall(Post::class); + + $response->assertUnauthorized(); + } + + public function testGetFieldsVisibleOnCreate(): void + { + $response = $this->novaActingAs(self::$user)->novaGetCreationFieldsAPICall(Post::class); + + $response->assertOk(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture('get_fields_visible_on_create_response', $response->json(), true); + } + + public static function getRunPostActionsData(): array + { + return [ + [ + 'action' => PublishPostAction::class, + 'request' => [ + 'resources' => '1,2', + ], + 'state' => 'run_publish_post_action_state', + ], + [ + 'action' => UnPublishPostAction::class, + 'request' => [ + 'resources' => '1,2', + ], + 'state' => 'run_un_publish_post_action_state', + ], + ]; + } + + #[DataProvider('getRunPostActionsData')] + public function testRunPostActions($action, $request, $state): void + { + $response = $this->novaActingAs(self::$user)->novaRunActionAPICall(Post::class, $action, $request); + + $response->assertOk(); + + $this->assertEmpty($response->getContent()); + + // TODO: Need to remove last argument after first successful start + self::$postState->assertChangesEqualsFixture($state, true); + } + + public static function getPostActionsData(): array + { + return [ + [ + 'resources' => [1, 2], + 'fixture' => 'get_post_actions_publish_post_action', + ], + [ + 'resources' => [1, 2], + 'fixture' => 'get_post_actions_un_publish_post_action', + ], + ]; + } + + #[DataProvider('getPostActionsData')] + public function testGetPostActions(array $resources, string $fixture): void + { + $response = $this->novaActingAs(self::$user)->novaGetActionsAPICall(Post::class, $resources); + + $response->assertOk(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture($fixture, $response->json(), true); + } + + public static function getPostFiltersData(): array + { + return [ + [ + 'request' => [ + 'TextField:description_field' => $this->novaSearchParams(['search term']), + ], + 'fixture' => 'filter_post_by_text_field', + ], + [ + 'request' => [ + 'RonasIT\Support\Tests\Support\NovaTestGeneratorTest\CreatedAtFilter' => $this->novaSearchParams(['search term']), + ], + 'fixture' => 'filter_post_by_created_at_filter', + ], + ]; + } + + #[DataProvider('getPostFiltersData')] + public function testFilterPost(array $request, string $fixture): void + { + $response = $this->novaActingAs(self::$user)->novaSearchResourceAPICall(Post::class, $request); + + $response->assertOk(); + + // TODO: Need to remove last argument after first successful start + $this->assertEqualsFixture($fixture, $response->json(), true); + } +} diff --git a/tests/fixtures/NovaTestGeneratorTest/post_dump.sql b/tests/fixtures/NovaTestGeneratorTest/post_dump.sql new file mode 100644 index 00000000..15371a53 --- /dev/null +++ b/tests/fixtures/NovaTestGeneratorTest/post_dump.sql @@ -0,0 +1,3 @@ +INSERT INTO "posts"(id, title, name, created_at, updated_at) VALUES + (1, 1, 1, '2016-10-20 11:05:00', '2016-10-20 11:05:00'); + diff --git a/tests/fixtures/NovaTestGeneratorTest/update_post_request.json b/tests/fixtures/NovaTestGeneratorTest/update_post_request.json new file mode 100644 index 00000000..538b482c --- /dev/null +++ b/tests/fixtures/NovaTestGeneratorTest/update_post_request.json @@ -0,0 +1,4 @@ +{ + "title": 1, + "name": 1 +} \ No newline at end of file From f3fa391a173fd50c33fb72554890711d69d0b7b3 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Fri, 11 Jul 2025 15:46:37 +0300 Subject: [PATCH 16/17] style:fix --- src/Generators/NovaTestGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index b009b9ce..ce8c4bdc 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -179,7 +179,7 @@ protected function allCommonNovaResources(): Generator $class = str_replace(['/', '.php'], ['\\', ''], $relativePath); - if($this->isValidCommonResourceCheck($class)){ + if ($this->isValidCommonResourceCheck($class)) { yield $class; } } From d0cc813915f8e2ad4805a16df0fb567febb1dcf0 Mon Sep 17 00:00:00 2001 From: Ruslan Guskov Date: Tue, 2 Sep 2025 15:45:58 +0300 Subject: [PATCH 17/17] refactor: remove useless from generator --- src/Generators/NovaTestGenerator.php | 81 +++++++++++++--------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/src/Generators/NovaTestGenerator.php b/src/Generators/NovaTestGenerator.php index ce8c4bdc..d37ec09b 100644 --- a/src/Generators/NovaTestGenerator.php +++ b/src/Generators/NovaTestGenerator.php @@ -41,7 +41,19 @@ public function generate(): void ); } - $this->isNovaResourceExists(); + $resource = $this->resourceName ?? $this->getNovaResource(); + + $this->shortNovaResourceName = Str::afterLast($resource, '\\'); + + $this->fullNovaResourcePath = "App\\Nova\\{$resource}"; + + if (!class_exists($this->fullNovaResourcePath)) { + $this->throwFailureException( + ClassNotExistsException::class, + "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", + "Create {$this->resourceName} Nova resource." + ); + } if ($this->classExists('nova', "Nova{$this->shortNovaResourceName}Test")) { $this->throwFailureException( @@ -132,78 +144,59 @@ protected function isFixtureNeeded($type): bool return true; } - protected function isNovaResourceExists(): void + protected function getNovaResource(): string { - $resource = $this->getNovaResource(); + $commonResources = $this->getCommonNovaResources(); - $this->shortNovaResourceName = Str::afterLast($resource, '\\'); - $this->fullNovaResourcePath = "App\\Nova\\{$resource}"; + if (count($commonResources) > 1) { + $commonResources = implode(', ', $commonResources); - if (!class_exists($this->fullNovaResourcePath)) { $this->throwFailureException( - ClassNotExistsException::class, - "Cannot create Nova{$this->shortNovaResourceName}Test cause {$this->resourceName} Nova resource does not exist.", - "Create {$this->resourceName} Nova resource." + EntityCreateException::class, + "Cannot create Nova{$this->model}Resource Test cause was found a lot of suitable resources: $commonResources", + "Please, use --resource-name option" ); } - } - - protected function getNovaResource(): ?string - { - if (!empty($this->resourceName)) { - return $this->resourceName; - } else { - $commonResources = $this->getCommonNovaResources(); - - if (count($commonResources) > 1) { - $commonResources = implode(', ', $commonResources); - $this->throwFailureException( - EntityCreateException::class, - "Cannot create Nova{$this->model}Resource Test cause was found a lot of suitable resources: $commonResources", - "Please, use --resource-name option" - ); - } - - return $commonResources[0]; - } + return array_pop($commonResources); } - protected function allCommonNovaResources(): Generator + protected function getNovaFiles(): Generator { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->novaPath)); foreach ($iterator as $file) { if ($file->isFile() && $file->getExtension() === 'php') { - $relativePath = Str::after($file->getPathname(), $this->novaPath . DIRECTORY_SEPARATOR); - - $class = str_replace(['/', '.php'], ['\\', ''], $relativePath); - - if ($this->isValidCommonResourceCheck($class)) { - yield $class; - } + yield $file; } } } protected function getCommonNovaResources(): array { - $commonNovaResources = $this->allCommonNovaResources(); - $resources = []; - foreach ($commonNovaResources as $resource) { - $resources[] = $resource; + foreach ($this->getNovaFiles() as $file) { + $relativePath = Str::after($file->getPathname(), $this->novaPath . DIRECTORY_SEPARATOR); + + $class = str_replace(['/', '.php'], ['\\', ''], $relativePath); + + if ($this->isNovaResource($class) && $this->isResourceNameContainModel($class)) { + $resources[] = $class; + } } return $resources; } - protected function isValidCommonResourceCheck(string $resource) + protected function isNovaResource(string $resource): bool { - $isContainModel = Str::afterLast(str_replace('Resource', '', $resource), '\\') === $this->model; + return is_subclass_of("App\\Nova\\{$resource}", "Laravel\\Nova\\Resource"); + } - return is_subclass_of("App\\Nova\\{$resource}", "Laravel\\Nova\\Resource") && $isContainModel; + protected function isResourceNameContainModel(string $resource): bool + { + return Str::afterLast(str_replace('Resource', '', $resource), '\\') === $this->model; } protected function collectFilters(): array