diff --git a/composer.json b/composer.json
index d4ac7f674f0e..ce24f8536bd3 100644
--- a/composer.json
+++ b/composer.json
@@ -104,7 +104,7 @@
"league/flysystem-read-only": "^3.3",
"league/flysystem-sftp-v3": "^3.0",
"mockery/mockery": "^1.5.1",
- "orchestra/testbench-core": "^8.4",
+ "orchestra/testbench-core": "^8.10",
"pda/pheanstalk": "^4.0",
"phpstan/phpstan": "^1.4.7",
"phpunit/phpunit": "^10.0.7",
diff --git a/tests/Integration/Generators/CastMakeCommandTest.php b/tests/Integration/Generators/CastMakeCommandTest.php
new file mode 100644
index 000000000000..dbbc5ad98dd1
--- /dev/null
+++ b/tests/Integration/Generators/CastMakeCommandTest.php
@@ -0,0 +1,37 @@
+artisan('make:cast', ['name' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Casts;',
+ 'use Illuminate\Contracts\Database\Eloquent\CastsAttributes;',
+ 'class Foo implements CastsAttributes',
+ 'public function get(Model $model, string $key, mixed $value, array $attributes): mixed',
+ 'public function set(Model $model, string $key, mixed $value, array $attributes): mixed',
+ ], 'app/Casts/Foo.php');
+ }
+
+ public function testItCanGenerateInboundCastFile()
+ {
+ $this->artisan('make:cast', ['name' => 'Foo', '--inbound' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Casts;',
+ 'use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;',
+ 'class Foo implements CastsInboundAttributes',
+ 'public function set(Model $model, string $key, mixed $value, array $attributes): mixed',
+ ], 'app/Casts/Foo.php');
+ }
+}
diff --git a/tests/Integration/Generators/ChannelMakeCommandTest.php b/tests/Integration/Generators/ChannelMakeCommandTest.php
new file mode 100644
index 000000000000..1c75ffda28c8
--- /dev/null
+++ b/tests/Integration/Generators/ChannelMakeCommandTest.php
@@ -0,0 +1,22 @@
+artisan('make:channel', ['name' => 'FooChannel'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Broadcasting;',
+ 'use Illuminate\Foundation\Auth\User;',
+ 'class FooChannel',
+ ], 'app/Broadcasting/FooChannel.php');
+ }
+}
diff --git a/tests/Integration/Generators/ComponentMakeCommandTest.php b/tests/Integration/Generators/ComponentMakeCommandTest.php
new file mode 100644
index 000000000000..fc1651ec7d95
--- /dev/null
+++ b/tests/Integration/Generators/ComponentMakeCommandTest.php
@@ -0,0 +1,53 @@
+artisan('make:component', ['name' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\View\Components;',
+ 'use Illuminate\View\Component;',
+ 'class Foo extends Component',
+ "return view('components.foo');",
+ ], 'app/View/Components/Foo.php');
+
+ $this->assertFilenameExists('resources/views/components/foo.blade.php');
+ $this->assertFilenameNotExists('tests/Feature/View/Components/FooTest.php');
+ }
+
+ public function testItCanGenerateInlineComponentFile()
+ {
+ $this->artisan('make:component', ['name' => 'Foo', '--inline' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\View\Components;',
+ 'use Illuminate\View\Component;',
+ 'class Foo extends Component',
+ "return <<<'blade'",
+ ], 'app/View/Components/Foo.php');
+
+ $this->assertFilenameNotExists('resources/views/components/foo.blade.php');
+ }
+
+ public function testItCanGenerateComponentFileWithTest()
+ {
+ $this->artisan('make:component', ['name' => 'Foo', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('app/View/Components/Foo.php');
+ $this->assertFilenameExists('resources/views/components/foo.blade.php');
+ $this->assertFilenameExists('tests/Feature/View/Components/FooTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/ControllerMakeCommandTest.php b/tests/Integration/Generators/ControllerMakeCommandTest.php
new file mode 100644
index 000000000000..c0c27c3b4e24
--- /dev/null
+++ b/tests/Integration/Generators/ControllerMakeCommandTest.php
@@ -0,0 +1,169 @@
+artisan('make:controller', ['name' => 'FooController'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class FooController extends Controller',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFileNotContains([
+ 'public function __invoke(Request $request)',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFilenameNotExists('tests/Feature/Http/Controllers/FooControllerTest.php');
+ }
+
+ public function testItCanGenerateControllerFileWithInvokableTypeOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--type' => 'invokable'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class FooController extends Controller',
+ 'public function __invoke(Request $request)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithInvokableOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--invokable' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class FooController extends Controller',
+ 'public function __invoke(Request $request)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithModelOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--model' => 'Foo'])
+ ->expectsQuestion('A App\Models\Foo model does not exist. Do you want to generate it?', false)
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use App\Models\Foo;',
+ 'public function index()',
+ 'public function create()',
+ 'public function store(Request $request)',
+ 'public function show(Foo $foo)',
+ 'public function edit(Foo $foo)',
+ 'public function update(Request $request, Foo $foo)',
+ 'public function destroy(Foo $foo)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithModelAndParentOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--model' => 'Bar', '--parent' => 'Foo'])
+ ->expectsQuestion('A App\Models\Foo model does not exist. Do you want to generate it?', false)
+ ->expectsQuestion('A App\Models\Bar model does not exist. Do you want to generate it?', false)
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use App\Models\Bar;',
+ 'use App\Models\Foo;',
+ 'public function index(Foo $foo)',
+ 'public function create(Foo $foo)',
+ 'public function store(Request $request, Foo $foo)',
+ 'public function show(Foo $foo, Bar $bar)',
+ 'public function edit(Foo $foo, Bar $bar)',
+ 'public function update(Request $request, Foo $foo, Bar $bar)',
+ 'public function destroy(Foo $foo, Bar $bar)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithApiOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--api' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class FooController extends Controller',
+ 'public function index()',
+ 'public function store(Request $request)',
+ 'public function update(Request $request, string $id)',
+ 'public function destroy(string $id)',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFileNotContains([
+ 'public function create()',
+ 'public function edit($id)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithInvokableIgnoresApiOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--api' => true, '--invokable' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class FooController extends Controller',
+ 'public function __invoke(Request $request)',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFileNotContains([
+ 'public function index()',
+ 'public function store(Request $request)',
+ 'public function update(Request $request, $id)',
+ 'public function destroy($id)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithApiAndModelOption()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--model' => 'Foo', '--api' => true])
+ ->expectsQuestion('A App\Models\Foo model does not exist. Do you want to generate it?', false)
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use App\Models\Foo;',
+ 'public function index()',
+ 'public function store(Request $request)',
+ 'public function show(Foo $foo)',
+ 'public function update(Request $request, Foo $foo)',
+ 'public function destroy(Foo $foo)',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFileNotContains([
+ 'public function create()',
+ 'public function edit(Foo $foo)',
+ ], 'app/Http/Controllers/FooController.php');
+ }
+
+ public function testItCanGenerateControllerFileWithTest()
+ {
+ $this->artisan('make:controller', ['name' => 'FooController', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('app/Http/Controllers/FooController.php');
+ $this->assertFilenameExists('tests/Feature/Http/Controllers/FooControllerTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/EventMakeCommandTest.php b/tests/Integration/Generators/EventMakeCommandTest.php
new file mode 100644
index 000000000000..eb3f05fa06c6
--- /dev/null
+++ b/tests/Integration/Generators/EventMakeCommandTest.php
@@ -0,0 +1,21 @@
+artisan('make:event', ['name' => 'FooCreated'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Events;',
+ 'class FooCreated',
+ ], 'app/Events/FooCreated.php');
+ }
+}
diff --git a/tests/Integration/Generators/ExceptionMakeCommandTest.php b/tests/Integration/Generators/ExceptionMakeCommandTest.php
new file mode 100644
index 000000000000..9876630c7452
--- /dev/null
+++ b/tests/Integration/Generators/ExceptionMakeCommandTest.php
@@ -0,0 +1,75 @@
+artisan('make:exception', ['name' => 'FooException'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Exceptions;',
+ 'use Exception;',
+ 'class FooException extends Exception',
+ ], 'app/Exceptions/FooException.php');
+
+ $this->assertFileNotContains([
+ 'public function report()',
+ 'public function render($request)',
+ ], 'app/Exceptions/FooException.php');
+ }
+
+ public function testItCanGenerateExceptionFileWithReportOption()
+ {
+ $this->artisan('make:exception', ['name' => 'FooException', '--report' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Exceptions;',
+ 'use Exception;',
+ 'class FooException extends Exception',
+ 'public function report()',
+ ], 'app/Exceptions/FooException.php');
+
+ $this->assertFileNotContains([
+ 'public function render($request)',
+ ], 'app/Exceptions/FooException.php');
+ }
+
+ public function testItCanGenerateExceptionFileWithRenderOption()
+ {
+ $this->artisan('make:exception', ['name' => 'FooException', '--render' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Exceptions;',
+ 'use Exception;',
+ 'class FooException extends Exception',
+ 'public function render(Request $request): Response',
+ ], 'app/Exceptions/FooException.php');
+
+ $this->assertFileNotContains([
+ 'public function report()',
+ ], 'app/Exceptions/FooException.php');
+ }
+
+ public function testItCanGenerateExceptionFileWithReportAndRenderOption()
+ {
+ $this->artisan('make:exception', ['name' => 'FooException', '--report' => true, '--render' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Exceptions;',
+ 'use Exception;',
+ 'class FooException extends Exception',
+ 'public function render(Request $request): Response',
+ 'public function report()',
+ ], 'app/Exceptions/FooException.php');
+ }
+}
diff --git a/tests/Integration/Generators/FactoryMakeCommandTest.php b/tests/Integration/Generators/FactoryMakeCommandTest.php
new file mode 100644
index 000000000000..02ec76943c99
--- /dev/null
+++ b/tests/Integration/Generators/FactoryMakeCommandTest.php
@@ -0,0 +1,24 @@
+artisan('make:factory', ['name' => 'FooFactory'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace Database\Factories;',
+ 'use Illuminate\Database\Eloquent\Factories\Factory;',
+ 'class FooFactory extends Factory',
+ 'public function definition()',
+ ], 'database/factories/FooFactory.php');
+ }
+}
diff --git a/tests/Integration/Generators/JobMakeCommandTest.php b/tests/Integration/Generators/JobMakeCommandTest.php
new file mode 100644
index 000000000000..0d1d1479128a
--- /dev/null
+++ b/tests/Integration/Generators/JobMakeCommandTest.php
@@ -0,0 +1,56 @@
+artisan('make:job', ['name' => 'FooCreated'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Jobs;',
+ 'use Illuminate\Bus\Queueable;',
+ 'use Illuminate\Contracts\Queue\ShouldQueue;',
+ 'use Illuminate\Foundation\Bus\Dispatchable;',
+ 'use Illuminate\Queue\InteractsWithQueue;',
+ 'use Illuminate\Queue\SerializesModels;',
+ 'class FooCreated implements ShouldQueue',
+ ], 'app/Jobs/FooCreated.php');
+
+ $this->assertFilenameNotExists('tests/Feature/Jobs/FooCreatedTest.php');
+ }
+
+ public function testItCanGenerateSyncJobFile()
+ {
+ $this->artisan('make:job', ['name' => 'FooCreated', '--sync' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Jobs;',
+ 'use Illuminate\Foundation\Bus\Dispatchable;',
+ 'class FooCreated',
+ ], 'app/Jobs/FooCreated.php');
+
+ $this->assertFileNotContains([
+ 'use Illuminate\Contracts\Queue\ShouldQueue;',
+ 'use Illuminate\Queue\InteractsWithQueue;',
+ 'use Illuminate\Queue\SerializesModels;',
+ ], 'app/Jobs/FooCreated.php');
+ }
+
+ public function testItCanGenerateJobFileWithTest()
+ {
+ $this->artisan('make:job', ['name' => 'FooCreated', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('app/Jobs/FooCreated.php');
+ $this->assertFilenameExists('tests/Feature/Jobs/FooCreatedTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/MailMakeCommandTest.php b/tests/Integration/Generators/MailMakeCommandTest.php
new file mode 100644
index 000000000000..8da9c0785ccc
--- /dev/null
+++ b/tests/Integration/Generators/MailMakeCommandTest.php
@@ -0,0 +1,58 @@
+artisan('make:mail', ['name' => 'FooMail'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Mail;',
+ 'use Illuminate\Mail\Mailable;',
+ 'class FooMail extends Mailable',
+ ], 'app/Mail/FooMail.php');
+
+ $this->assertFilenameNotExists('resources/views/foo-mail.blade.php');
+ $this->assertFilenameNotExists('tests/Feature/Mail/FooMailTest.php');
+ }
+
+ public function testItCanGenerateMailFileWithMarkdownOption()
+ {
+ $this->artisan('make:mail', ['name' => 'FooMail', '--markdown' => 'foo-mail'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Mail;',
+ 'use Illuminate\Mail\Mailable;',
+ 'class FooMail extends Mailable',
+ 'return new Content(',
+ "markdown: 'foo-mail',",
+ ], 'app/Mail/FooMail.php');
+
+ $this->assertFileContains([
+ '',
+ '',
+ '',
+ '',
+ ], 'resources/views/foo-mail.blade.php');
+ }
+
+ public function testItCanGenerateMailFileWithTest()
+ {
+ $this->artisan('make:mail', ['name' => 'FooMail', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('app/Mail/FooMail.php');
+ $this->assertFilenameNotExists('resources/views/foo-mail.blade.php');
+ $this->assertFilenameExists('tests/Feature/Mail/FooMailTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/MiddlewareMakeCommandTest.php b/tests/Integration/Generators/MiddlewareMakeCommandTest.php
new file mode 100644
index 000000000000..604dd8c0e921
--- /dev/null
+++ b/tests/Integration/Generators/MiddlewareMakeCommandTest.php
@@ -0,0 +1,37 @@
+artisan('make:middleware', ['name' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Middleware;',
+ 'use Closure;',
+ 'use Illuminate\Http\Request;',
+ 'class Foo',
+ 'public function handle(Request $request, Closure $next)',
+ 'return $next($request);',
+ ], 'app/Http/Middleware/Foo.php');
+
+ $this->assertFilenameNotExists('tests/Feature/Http/Middleware/FooTest.php');
+ }
+
+ public function testItCanGenerateMiddlewareFile_with_tests()
+ {
+ $this->artisan('make:middleware', ['name' => 'Foo', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('app/Http/Middleware/Foo.php');
+ $this->assertFilenameExists('tests/Feature/Http/Middleware/FooTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/MigrateMakeCommandTest.php b/tests/Integration/Generators/MigrateMakeCommandTest.php
new file mode 100644
index 000000000000..fd2ef65adc8f
--- /dev/null
+++ b/tests/Integration/Generators/MigrateMakeCommandTest.php
@@ -0,0 +1,56 @@
+artisan('make:migration', ['name' => 'AddBarToFoosTable'])
+ ->assertExitCode(0);
+
+ $this->assertMigrationFileContains([
+ 'use Illuminate\Database\Migrations\Migration;',
+ 'return new class extends Migration',
+ 'Schema::table(\'foos\', function (Blueprint $table) {',
+ ], 'add_bar_to_foos_table.php');
+ }
+
+ public function testItCanGenerateMigrationFileWIthTableOption()
+ {
+ $this->artisan('make:migration', ['name' => 'AddBarToFoosTable', '--table' => 'foobar'])
+ ->assertExitCode(0);
+
+ $this->assertMigrationFileContains([
+ 'use Illuminate\Database\Migrations\Migration;',
+ 'return new class extends Migration',
+ 'Schema::table(\'foobar\', function (Blueprint $table) {',
+ ], 'add_bar_to_foos_table.php');
+ }
+
+ public function testItCanGenerateMigrationFileUsingCreateKeyword()
+ {
+ $this->artisan('make:migration', ['name' => 'CreateFoosTable'])
+ ->assertExitCode(0);
+
+ $this->assertMigrationFileContains([
+ 'use Illuminate\Database\Migrations\Migration;',
+ 'return new class extends Migration',
+ 'Schema::create(\'foos\', function (Blueprint $table) {',
+ 'Schema::dropIfExists(\'foos\');',
+ ], 'create_foos_table.php');
+ }
+
+ public function testItCanGenerateMigrationFileUsingCreateOption()
+ {
+ $this->artisan('make:migration', ['name' => 'FoosTable', '--create' => 'foobar'])
+ ->assertExitCode(0);
+
+ $this->assertMigrationFileContains([
+ 'use Illuminate\Database\Migrations\Migration;',
+ 'return new class extends Migration',
+ 'Schema::create(\'foobar\', function (Blueprint $table) {',
+ 'Schema::dropIfExists(\'foobar\');',
+ ], 'foos_table.php');
+ }
+}
diff --git a/tests/Integration/Generators/ModelMakeCommandTest.php b/tests/Integration/Generators/ModelMakeCommandTest.php
new file mode 100644
index 000000000000..3ab287ccbc6f
--- /dev/null
+++ b/tests/Integration/Generators/ModelMakeCommandTest.php
@@ -0,0 +1,182 @@
+artisan('make:model', ['name' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Foo extends Model',
+ ], 'app/Models/Foo.php');
+
+ $this->assertFilenameNotExists('app/Http/Controllers/FooController.php');
+ $this->assertFilenameNotExists('database/factories/FooFactory.php');
+ $this->assertFilenameNotExists('database/seeders/FooSeeder.php');
+ $this->assertFilenameNotExists('tests/Feature/Models/FooTest.php');
+ }
+
+ public function testItCanGenerateModelFileWithPivotOption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--pivot' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Relations\Pivot;',
+ 'class Foo extends Pivot',
+ ], 'app/Models/Foo.php');
+ }
+
+ public function testItCanGenerateModelFileWithMorphPivotOption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--morph-pivot' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Relations\MorphPivot;',
+ 'class Foo extends MorphPivot',
+ ], 'app/Models/Foo.php');
+ }
+
+ public function testItCanGenerateModelFileWithControllerOption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--controller' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Foo extends Model',
+ ], 'app/Models/Foo.php');
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class FooController extends Controller',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFileNotContains([
+ 'use App\Models\Foo;',
+ 'public function index()',
+ 'public function create()',
+ 'public function store(Request $request)',
+ 'public function show(Foo $foo)',
+ 'public function edit(Foo $foo)',
+ 'public function update(Request $request, Foo $foo)',
+ 'public function destroy(Foo $foo)',
+ ], 'app/Http/Controllers/FooController.php');
+
+ $this->assertFilenameNotExists('database/factories/FooFactory.php');
+ $this->assertFilenameNotExists('database/seeders/FooSeeder.php');
+ }
+
+ public function testItCanGenerateModelFileWithFactoryOption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--factory' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Foo extends Model',
+ ], 'app/Models/Foo.php');
+
+ $this->assertFilenameNotExists('app/Http/Controllers/FooController.php');
+ $this->assertFilenameExists('database/factories/FooFactory.php');
+ $this->assertFilenameNotExists('database/seeders/FooSeeder.php');
+ }
+
+ public function testItCanGenerateModelFileWithMigrationOption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--migration' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Foo extends Model',
+ ], 'app/Models/Foo.php');
+
+ $this->assertMigrationFileContains([
+ 'use Illuminate\Database\Migrations\Migration;',
+ 'return new class extends Migration',
+ 'Schema::create(\'foos\', function (Blueprint $table) {',
+ 'Schema::dropIfExists(\'foos\');',
+ ], 'create_foos_table.php');
+
+ $this->assertFilenameNotExists('app/Http/Controllers/FooController.php');
+ $this->assertFilenameNotExists('database/factories/FooFactory.php');
+ $this->assertFilenameNotExists('database/seeders/FooSeeder.php');
+ }
+
+ public function testItCanGenerateModelFileWithSeederption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--seed' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Foo extends Model',
+ ], 'app/Models/Foo.php');
+
+ $this->assertFilenameNotExists('app/Http/Controllers/FooController.php');
+ $this->assertFilenameNotExists('database/factories/FooFactory.php');
+ $this->assertFilenameExists('database/seeders/FooSeeder.php');
+ }
+
+ public function testItCanGenerateNestedModelFileWithControllerOption()
+ {
+ $this->artisan('make:model', ['name' => 'Foo/Bar', '--controller' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models\Foo;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Bar extends Model',
+ ], 'app/Models/Foo/Bar.php');
+
+ $this->assertFileContains([
+ 'namespace App\Http\Controllers;',
+ 'use Illuminate\Http\Request;',
+ 'class BarController extends Controller',
+ ], 'app/Http/Controllers/BarController.php');
+
+ $this->assertFilenameNotExists('database/factories/FooFactory.php');
+ $this->assertFilenameNotExists('database/seeders/FooSeeder.php');
+ }
+
+ public function testItCanGenerateModelFileWithTest()
+ {
+ $this->artisan('make:model', ['name' => 'Foo', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Models;',
+ 'use Illuminate\Database\Eloquent\Model;',
+ 'class Foo extends Model',
+ ], 'app/Models/Foo.php');
+
+ $this->assertFilenameNotExists('app/Http/Controllers/FooController.php');
+ $this->assertFilenameNotExists('database/factories/FooFactory.php');
+ $this->assertFilenameNotExists('database/seeders/FooSeeder.php');
+ $this->assertFilenameExists('tests/Feature/Models/FooTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/NotificationMakeCommandTest.php b/tests/Integration/Generators/NotificationMakeCommandTest.php
new file mode 100644
index 000000000000..b2381c6811ba
--- /dev/null
+++ b/tests/Integration/Generators/NotificationMakeCommandTest.php
@@ -0,0 +1,54 @@
+artisan('make:notification', ['name' => 'FooNotification'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Notifications;',
+ 'use Illuminate\Notifications\Notification;',
+ 'class FooNotification extends Notification',
+ 'return (new MailMessage)',
+ ], 'app/Notifications/FooNotification.php');
+
+ $this->assertFilenameNotExists('resources/views/foo-notification.blade.php');
+ $this->assertFilenameNotExists('tests/Feature/Notifications/FooNotificationTest.php');
+ }
+
+ public function testItCanGenerateNotificationFileWithMarkdownOption()
+ {
+ $this->artisan('make:notification', ['name' => 'FooNotification', '--markdown' => 'foo-notification'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Notifications;',
+ 'class FooNotification extends Notification',
+ "return (new MailMessage)->markdown('foo-notification')",
+ ], 'app/Notifications/FooNotification.php');
+
+ $this->assertFileContains([
+ '',
+ ], 'resources/views/foo-notification.blade.php');
+ }
+
+ public function testItCanGenerateNotificationFileWithTest()
+ {
+ $this->artisan('make:notification', ['name' => 'FooNotification', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('app/Notifications/FooNotification.php');
+ $this->assertFilenameNotExists('resources/views/foo-notification.blade.php');
+ $this->assertFilenameExists('tests/Feature/Notifications/FooNotificationTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/ObserverMakeCommandTest.php b/tests/Integration/Generators/ObserverMakeCommandTest.php
new file mode 100644
index 000000000000..5ba618acca0f
--- /dev/null
+++ b/tests/Integration/Generators/ObserverMakeCommandTest.php
@@ -0,0 +1,38 @@
+artisan('make:observer', ['name' => 'FooObserver'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Observers;',
+ 'class FooObserver',
+ ], 'app/Observers/FooObserver.php');
+ }
+
+ public function testItCanGenerateObserverFileWithModel()
+ {
+ $this->artisan('make:observer', ['name' => 'FooObserver', '--model' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Observers;',
+ 'use App\Models\Foo;',
+ 'class FooObserver',
+ 'public function created(Foo $foo)',
+ 'public function updated(Foo $foo)',
+ 'public function deleted(Foo $foo)',
+ 'public function restored(Foo $foo)',
+ 'public function forceDeleted(Foo $foo)',
+ ], 'app/Observers/FooObserver.php');
+ }
+}
diff --git a/tests/Integration/Generators/PolicyMakeCommandTest.php b/tests/Integration/Generators/PolicyMakeCommandTest.php
new file mode 100644
index 000000000000..77f0cbbed049
--- /dev/null
+++ b/tests/Integration/Generators/PolicyMakeCommandTest.php
@@ -0,0 +1,42 @@
+artisan('make:policy', ['name' => 'FooPolicy'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Policies;',
+ 'use Illuminate\Foundation\Auth\User;',
+ 'class FooPolicy',
+ ], 'app/Policies/FooPolicy.php');
+ }
+
+ public function testItCanGeneratePolicyFileWithModelOption()
+ {
+ $this->artisan('make:policy', ['name' => 'FooPolicy', '--model' => 'Post'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Policies;',
+ 'use App\Models\Post;',
+ 'use Illuminate\Foundation\Auth\User;',
+ 'class FooPolicy',
+ 'public function viewAny(User $user)',
+ 'public function view(User $user, Post $post)',
+ 'public function create(User $user)',
+ 'public function update(User $user, Post $post)',
+ 'public function delete(User $user, Post $post)',
+ 'public function restore(User $user, Post $post)',
+ 'public function forceDelete(User $user, Post $post)',
+ ], 'app/Policies/FooPolicy.php');
+ }
+}
diff --git a/tests/Integration/Generators/ProviderMakeCommandTest.php b/tests/Integration/Generators/ProviderMakeCommandTest.php
new file mode 100644
index 000000000000..9f0416c6d312
--- /dev/null
+++ b/tests/Integration/Generators/ProviderMakeCommandTest.php
@@ -0,0 +1,24 @@
+artisan('make:provider', ['name' => 'FooServiceProvider'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Providers;',
+ 'use Illuminate\Support\ServiceProvider;',
+ 'class FooServiceProvider extends ServiceProvider',
+ 'public function register()',
+ 'public function boot()',
+ ], 'app/Providers/FooServiceProvider.php');
+ }
+}
diff --git a/tests/Integration/Generators/RequestMakeCommandTest.php b/tests/Integration/Generators/RequestMakeCommandTest.php
new file mode 100644
index 000000000000..584be86b58a3
--- /dev/null
+++ b/tests/Integration/Generators/RequestMakeCommandTest.php
@@ -0,0 +1,22 @@
+artisan('make:request', ['name' => 'FooRequest'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Requests;',
+ 'use Illuminate\Foundation\Http\FormRequest;',
+ 'class FooRequest extends FormRequest',
+ ], 'app/Http/Requests/FooRequest.php');
+ }
+}
diff --git a/tests/Integration/Generators/ResourceMakeCommandTest.php b/tests/Integration/Generators/ResourceMakeCommandTest.php
new file mode 100644
index 000000000000..b50b40872a85
--- /dev/null
+++ b/tests/Integration/Generators/ResourceMakeCommandTest.php
@@ -0,0 +1,37 @@
+artisan('make:resource', ['name' => 'FooResource'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Resources;',
+ 'use Illuminate\Http\Resources\Json\JsonResource;',
+ 'class FooResource extends JsonResource',
+ ], 'app/Http/Resources/FooResource.php');
+ }
+
+ /** @test */
+ public function it_can_generate_resource_collection_file()
+ {
+ $this->artisan('make:resource', ['name' => 'FooResourceCollection', '--collection' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Http\Resources;',
+ 'use Illuminate\Http\Resources\Json\ResourceCollection;',
+ 'class FooResourceCollection extends ResourceCollection',
+ ], 'app/Http/Resources/FooResourceCollection.php');
+ }
+}
diff --git a/tests/Integration/Generators/RuleMakeCommandTest.php b/tests/Integration/Generators/RuleMakeCommandTest.php
new file mode 100644
index 000000000000..770672a71937
--- /dev/null
+++ b/tests/Integration/Generators/RuleMakeCommandTest.php
@@ -0,0 +1,49 @@
+artisan('make:rule', ['name' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Rules;',
+ 'use Illuminate\Contracts\Validation\ValidationRule;',
+ 'class Foo implements ValidationRule',
+ ], 'app/Rules/Foo.php');
+ }
+
+ public function testItCanGenerateInvokableRuleFile()
+ {
+ $this->artisan('make:rule', ['name' => 'Foo'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Rules;',
+ 'use Illuminate\Contracts\Validation\ValidationRule;',
+ 'class Foo implements ValidationRule',
+ 'public function validate(string $attribute, mixed $value, Closure $fail): void',
+ ], 'app/Rules/Foo.php');
+ }
+
+ public function testItCanGenerateImplicitRuleFile()
+ {
+ $this->artisan('make:rule', ['name' => 'Foo', '--implicit' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace App\Rules;',
+ 'use Illuminate\Contracts\Validation\ValidationRule;',
+ 'class Foo implements ValidationRule',
+ 'public $implicit = true;',
+ 'public function validate(string $attribute, mixed $value, Closure $fail): void',
+ ], 'app/Rules/Foo.php');
+ }
+}
diff --git a/tests/Integration/Generators/SeederMakeCommandTest.php b/tests/Integration/Generators/SeederMakeCommandTest.php
new file mode 100644
index 000000000000..72702000ecb3
--- /dev/null
+++ b/tests/Integration/Generators/SeederMakeCommandTest.php
@@ -0,0 +1,23 @@
+artisan('make:seeder', ['name' => 'FooSeeder'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace Database\Seeders;',
+ 'use Illuminate\Database\Seeder;',
+ 'class FooSeeder extends Seeder',
+ 'public function run()',
+ ], 'database/seeders/FooSeeder.php');
+ }
+}
diff --git a/tests/Integration/Generators/TestCase.php b/tests/Integration/Generators/TestCase.php
new file mode 100644
index 000000000000..19bce44b7ddb
--- /dev/null
+++ b/tests/Integration/Generators/TestCase.php
@@ -0,0 +1,10 @@
+artisan('make:test', ['name' => 'FooTest'])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace Tests\Feature;',
+ 'use Illuminate\Foundation\Testing\RefreshDatabase;',
+ 'use Illuminate\Foundation\Testing\WithFaker;',
+ 'use Tests\TestCase;',
+ 'class FooTest extends TestCase',
+ ], 'tests/Feature/FooTest.php');
+ }
+
+ public function testItCanGenerateUnitTest()
+ {
+ $this->artisan('make:test', ['name' => 'FooTest', '--unit' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'namespace Tests\Unit;',
+ 'use PHPUnit\Framework\TestCase;',
+ 'class FooTest extends TestCase',
+ ], 'tests/Unit/FooTest.php');
+ }
+
+ public function testItCanGenerateFeatureTestUsingPest()
+ {
+ $this->artisan('make:test', ['name' => 'FooTest', '--pest' => true])
+ ->assertExitCode(0);
+
+ $this->assertFileContains([
+ 'test(\'example\', function () {',
+ '$response = $this->get(\'/\');',
+ '$response->assertStatus(200);',
+ ], 'tests/Feature/FooTest.php');
+ }
+
+ public function testItCanGenerateUnitTestUsingPest()
+ {
+ $this->artisan('make:test', ['name' => 'FooTest', '--unit' => true, '--pest' => true])
+ ->assertExitCode(0);
+ $this->assertFileContains([
+ 'test(\'example\', function () {',
+ 'expect(true)->toBeTrue();',
+ ], 'tests/Unit/FooTest.php');
+ }
+}
diff --git a/tests/Integration/Generators/ViewMakeCommandTest.php b/tests/Integration/Generators/ViewMakeCommandTest.php
new file mode 100644
index 000000000000..202bc15656ab
--- /dev/null
+++ b/tests/Integration/Generators/ViewMakeCommandTest.php
@@ -0,0 +1,29 @@
+artisan('make:view', ['name' => 'foo'])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('resources/views/foo.blade.php');
+ $this->assertFilenameNotExists('tests/Feature/View/FooTest.php');
+ }
+
+ public function testItCanGenerateViewFileWithTest()
+ {
+ $this->artisan('make:view', ['name' => 'foo', '--test' => true])
+ ->assertExitCode(0);
+
+ $this->assertFilenameExists('resources/views/foo.blade.php');
+ $this->assertFilenameExists('tests/Feature/View/FooTest.php');
+ }
+}