changeset 37:116b36f5e73b ls_dev_2025_09

Adding support for tests. It's pretty basic but we can improve later.
author Luka Sitas <sitas.luka.97@gmail.com>
date Thu, 25 Sep 2025 19:58:01 -0400
parents 76584181267a
children c062f013fd19
files src/Generator/Generator.php src/Generator/Test/TestGenerator.php src/Generator/Test/stubs/test.stub src/MagicForgerServiceProvider.php src/Replacer/Replacer.php
diffstat 5 files changed, 237 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/Generator/Generator.php	Sat Sep 20 17:14:29 2025 -0400
+++ b/src/Generator/Generator.php	Thu Sep 25 19:58:01 2025 -0400
@@ -82,6 +82,10 @@
         if ($this->option('route')) {
             $this->createRoute();
         }
+
+        if ($this->option('test')) {
+            $this->createTest();
+        }
     }
 
     /**
@@ -96,7 +100,8 @@
             ['request', 'r', InputOption::VALUE_NONE, 'Generate base request classes for the table.'],
             ['view', '', InputOption::VALUE_NONE, 'Generate base views for the table.'],
             ['route', 'w', InputOption::VALUE_NONE, 'Generate base routes classes for the table.'],
-            ['factory', 'f', InputOption::VALUE_NONE, 'Generate base factory classes for the table.'],
+            ['factory', 'F', InputOption::VALUE_NONE, 'Generate base factory classes for the table.'],
+            ['test', 't', InputOption::VALUE_NONE, 'Generate base test classes for the table.'],
         ]);
     }
 
@@ -136,4 +141,9 @@
     {
         $this->call('mf:factory', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
     }
+
+    protected function createTest()
+    {
+        $this->call('mf:test', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Test/TestGenerator.php	Thu Sep 25 19:58:01 2025 -0400
@@ -0,0 +1,79 @@
+<?php
+
+namespace Wizard\MagicForger\Generator\Test;
+
+use Symfony\Component\Console\Attribute\AsCommand;
+use Wizard\MagicForger\Generator\BaseGenerator;
+use Wizard\MagicForger\Replacer;
+use Illuminate\Support\Str;
+
+#[AsCommand(name: 'mf:test')]
+class TestGenerator extends BaseGenerator
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $name = 'mf:test';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Generates the Test File for a table.';
+
+    /**
+     * The type of class being generated.
+     *
+     * @var string
+     */
+    protected $type = 'Test';
+
+    /**
+     * Execute the console command.
+     */
+    public function handle()
+    {
+			parent::handle();
+    }
+
+    /**
+     * Get the stub file for the generator.
+     *
+     * @return string
+     */
+    protected function getStub()
+    {
+        return $this->resolveStubPath('/stubs/test.stub');
+    }
+
+    /**
+     * Resolve the fully-qualified path to the stub.
+     *
+     * @param  string  $stub
+     * @return string
+     */
+    protected function resolveStubPath($stub)
+    {
+        return is_file($customPath = $this->laravel->basePath(trim($stub, '/')))
+            ? $customPath
+            : __DIR__.$stub;
+    }
+
+    protected function getClassName($name)
+    {
+        return $this->test_name($name);
+    }
+
+    /**
+     * Get the stub file for the generator.
+     *
+     * @return string
+     */
+    protected function getPath($name = null)
+    {
+        return str_replace(['App\\', '\\'], ['app/', '/'], $this->getTestNamespace() . '/' . $this->test_name($this->getTableInput()) . '.php');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Test/stubs/test.stub	Thu Sep 25 19:58:01 2025 -0400
@@ -0,0 +1,127 @@
+<?php
+
+namespace Tests\CRUD\{{ model }};
+
+use {{ namespacedModel }};
+use App\Models\User;
+use Wizard\Framework\Tests\TestCase;
+
+class {{ class }} extends TestCase
+{
+    /* use RefreshDatabase; */
+
+    public function test_{{ modelVariable }}_crud_index_access(): void
+    {
+        $response = $this
+					->get(route('{{ tableName }}.index'));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_get_data_access(): void
+    {
+        $response = $this
+					->post(route('{{ tableName }}.get_data'));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_create_access(): void
+    {
+				$response = $this
+					->get(route('{{ tableName }}.create'));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_edit_access(): void
+    {
+		$item = {{ model }}::factory()->create();
+
+        $response = $this
+					->get(route('{{ tableName }}.edit', $item));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_create_usage(): void
+    {
+        $item = {{ model }}::factory()->make();
+
+        $response = $this
+            ->from(route('{{ tableName }}.create'))
+            ->post(route('{{ tableName }}.store'),
+                $item->toArray()
+            );
+
+        $response
+            ->assertSessionHasNoErrors()
+            ->assertRedirect(route('{{ tableName }}.index'));
+
+        $this->assertDatabaseHas('{{ tableName }}', $item->toArray());
+    }
+
+   public function test_{{ modelVariable }}_crud_create_invalid_data(): void
+   {
+       $response = $this
+           ->from(route('{{ tableName }}.create'))
+           ->post(route('{{ tableName }}.store'), []);
+
+       $response
+           ->assertSessionHasErrors()
+           ->assertRedirect(route('{{ tableName }}.create'));
+
+       // Make sure no entry was added
+       $this->assertDatabaseCount('{{ tableName }}', 0);
+   }
+
+   public function test_{{ modelVariable }}_crud_update_usage(): void
+   {
+       $item = {{ model }}::factory()->create();
+
+       $updateData = {{ model }}::factory()->make()->toArray();
+
+       $response = $this
+           ->from(route('{{ tableName }}.edit', $item))
+           ->put(route('{{ tableName }}.update', $item), $updateData);
+
+       $response
+           ->assertSessionHasNoErrors()
+           ->assertRedirect(route('{{ tableName }}.index'));
+
+       $this->assertDatabaseHas('{{ tableName }}', $updateData);
+   }
+
+   public function test_{{ modelVariable }}_crud_edit_invalid_data(): void
+   {
+       $item = {{ model }}::factory()->create();
+
+       $response = $this
+           ->from(route('{{ tableName }}.edit', $item))
+           ->put(route('{{ tableName }}.update', $item), []);
+
+       $response
+           ->assertSessionHasErrors()
+           ->assertRedirect(route('{{ tableName }}.edit', $item));
+
+       // Make sure no entry was added
+       $this->assertDatabaseHas('games', array_intersect(array_flip($item->getFillable()), $item->toArray()));
+   }
+
+   public function test_{{ modelVariable }}_crud_delete_usage(): void
+   {
+       $item = {{ model }}::factory()->create();
+
+       $response = $this
+           ->delete(route('{{ tableName }}.destroy', $item));
+
+       $response
+           ->assertSessionHasNoErrors()
+           ->assertRedirect(route('{{ tableName }}.index'));
+
+       $this->assertSoftDeleted('{{ tableName }}', [
+           'id' => $item->id,
+       ]);
+   }
+
+}
--- a/src/MagicForgerServiceProvider.php	Sat Sep 20 17:14:29 2025 -0400
+++ b/src/MagicForgerServiceProvider.php	Thu Sep 25 19:58:01 2025 -0400
@@ -12,6 +12,7 @@
 use Wizard\MagicForger\Generator\Requests\StoreRequestGenerator;
 use Wizard\MagicForger\Generator\Requests\UpdateRequestGenerator;
 use Wizard\MagicForger\Generator\Route\RouteGenerator;
+use Wizard\MagicForger\Generator\Test\TestGenerator;
 use Wizard\MagicForger\Generator\View\ViewGenerator;
 use Wizard\MagicForger\Generator\View\IndexViewGenerator;
 use Wizard\MagicForger\Generator\View\CreateEditViewGenerator;
@@ -39,6 +40,7 @@
                 CreateEditViewGenerator::class,
                 ShowViewGenerator::class,
 								FactoryGenerator::class,
+								TestGenerator::class,
             ]);
         }
 
--- a/src/Replacer/Replacer.php	Sat Sep 20 17:14:29 2025 -0400
+++ b/src/Replacer/Replacer.php	Thu Sep 25 19:58:01 2025 -0400
@@ -165,6 +165,14 @@
         return Str::singular(Str::studly($name)) . 'Factory';
     }
 
+    /**
+     * Generate test name in Studly case.
+     */
+    public function test_name(string $name): string
+    {
+        return Str::singular(Str::studly($name)) . 'Test';
+    }
+
     // Namespace Methods
     // These methods handle the formation of various namespaces used within the replacements.
 
@@ -285,6 +293,16 @@
     }
 
     /**
+     * Get the test namespace.
+     */
+    public function getTestNamespace(string $name = ''): string
+    {
+        return base_path()
+				. DIRECTORY_SEPARATOR . 'tests' 
+				. DIRECTORY_SEPARATOR . 'CRUD' ;
+    }
+
+    /**
      * Get the request uses string for replacement.
      */
     public function getRequestUses(string $name): string