mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 06:31:10 -05:00
feat: Implement rides management with CRUD functionality
- Added rides index view with search and filter options. - Created rides show view to display ride details. - Implemented API routes for rides. - Developed authentication routes for user registration, login, and email verification. - Created tests for authentication, email verification, password reset, and user profile management. - Added feature tests for rides and operators, including creation, updating, deletion, and searching. - Implemented soft deletes and caching for rides and operators. - Enhanced manufacturer and operator model tests for various functionalities.
This commit is contained in:
86
tests/Feature/Auth/AuthenticationTest.php
Normal file
86
tests/Feature/Auth/AuthenticationTest.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Volt\Volt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AuthenticationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_login_screen_can_be_rendered(): void
|
||||
{
|
||||
$response = $this->get('/login');
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSeeVolt('pages.auth.login');
|
||||
}
|
||||
|
||||
public function test_users_can_authenticate_using_the_login_screen(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$component = Volt::test('pages.auth.login')
|
||||
->set('form.email', $user->email)
|
||||
->set('form.password', 'password');
|
||||
|
||||
$component->call('login');
|
||||
|
||||
$component
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect(route('dashboard', absolute: false));
|
||||
|
||||
$this->assertAuthenticated();
|
||||
}
|
||||
|
||||
public function test_users_can_not_authenticate_with_invalid_password(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$component = Volt::test('pages.auth.login')
|
||||
->set('form.email', $user->email)
|
||||
->set('form.password', 'wrong-password');
|
||||
|
||||
$component->call('login');
|
||||
|
||||
$component
|
||||
->assertHasErrors()
|
||||
->assertNoRedirect();
|
||||
|
||||
$this->assertGuest();
|
||||
}
|
||||
|
||||
public function test_navigation_menu_can_be_rendered(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get('/dashboard');
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSeeVolt('layout.navigation');
|
||||
}
|
||||
|
||||
public function test_users_can_logout(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('layout.navigation');
|
||||
|
||||
$component->call('logout');
|
||||
|
||||
$component
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertGuest();
|
||||
}
|
||||
}
|
||||
60
tests/Feature/Auth/EmailVerificationTest.php
Normal file
60
tests/Feature/Auth/EmailVerificationTest.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Tests\TestCase;
|
||||
|
||||
class EmailVerificationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_email_verification_screen_can_be_rendered(): void
|
||||
{
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/verify-email');
|
||||
|
||||
$response
|
||||
->assertSeeVolt('pages.auth.verify-email')
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_email_can_be_verified(): void
|
||||
{
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$response = $this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertDispatched(Verified::class);
|
||||
$this->assertTrue($user->fresh()->hasVerifiedEmail());
|
||||
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
|
||||
}
|
||||
|
||||
public function test_email_is_not_verified_with_invalid_hash(): void
|
||||
{
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1('wrong-email')]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
$this->assertFalse($user->fresh()->hasVerifiedEmail());
|
||||
}
|
||||
}
|
||||
56
tests/Feature/Auth/PasswordConfirmationTest.php
Normal file
56
tests/Feature/Auth/PasswordConfirmationTest.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Volt\Volt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordConfirmationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_confirm_password_screen_can_be_rendered(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/confirm-password');
|
||||
|
||||
$response
|
||||
->assertSeeVolt('pages.auth.confirm-password')
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_password_can_be_confirmed(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('pages.auth.confirm-password')
|
||||
->set('password', 'password');
|
||||
|
||||
$component->call('confirmPassword');
|
||||
|
||||
$component
|
||||
->assertRedirect('/dashboard')
|
||||
->assertHasNoErrors();
|
||||
}
|
||||
|
||||
public function test_password_is_not_confirmed_with_invalid_password(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('pages.auth.confirm-password')
|
||||
->set('password', 'wrong-password');
|
||||
|
||||
$component->call('confirmPassword');
|
||||
|
||||
$component
|
||||
->assertNoRedirect()
|
||||
->assertHasErrors('password');
|
||||
}
|
||||
}
|
||||
84
tests/Feature/Auth/PasswordResetTest.php
Normal file
84
tests/Feature/Auth/PasswordResetTest.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Livewire\Volt\Volt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordResetTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_reset_password_link_screen_can_be_rendered(): void
|
||||
{
|
||||
$response = $this->get('/forgot-password');
|
||||
|
||||
$response
|
||||
->assertSeeVolt('pages.auth.forgot-password')
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_reset_password_link_can_be_requested(): void
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Volt::test('pages.auth.forgot-password')
|
||||
->set('email', $user->email)
|
||||
->call('sendPasswordResetLink');
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class);
|
||||
}
|
||||
|
||||
public function test_reset_password_screen_can_be_rendered(): void
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Volt::test('pages.auth.forgot-password')
|
||||
->set('email', $user->email)
|
||||
->call('sendPasswordResetLink');
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) {
|
||||
$response = $this->get('/reset-password/'.$notification->token);
|
||||
|
||||
$response
|
||||
->assertSeeVolt('pages.auth.reset-password')
|
||||
->assertStatus(200);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public function test_password_can_be_reset_with_valid_token(): void
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Volt::test('pages.auth.forgot-password')
|
||||
->set('email', $user->email)
|
||||
->call('sendPasswordResetLink');
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
|
||||
$component = Volt::test('pages.auth.reset-password', ['token' => $notification->token])
|
||||
->set('email', $user->email)
|
||||
->set('password', 'password')
|
||||
->set('password_confirmation', 'password');
|
||||
|
||||
$component->call('resetPassword');
|
||||
|
||||
$component
|
||||
->assertRedirect('/login')
|
||||
->assertHasNoErrors();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
50
tests/Feature/Auth/PasswordUpdateTest.php
Normal file
50
tests/Feature/Auth/PasswordUpdateTest.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Livewire\Volt\Volt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordUpdateTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_password_can_be_updated(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('profile.update-password-form')
|
||||
->set('current_password', 'password')
|
||||
->set('password', 'new-password')
|
||||
->set('password_confirmation', 'new-password')
|
||||
->call('updatePassword');
|
||||
|
||||
$component
|
||||
->assertHasNoErrors()
|
||||
->assertNoRedirect();
|
||||
|
||||
$this->assertTrue(Hash::check('new-password', $user->refresh()->password));
|
||||
}
|
||||
|
||||
public function test_correct_password_must_be_provided_to_update_password(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('profile.update-password-form')
|
||||
->set('current_password', 'wrong-password')
|
||||
->set('password', 'new-password')
|
||||
->set('password_confirmation', 'new-password')
|
||||
->call('updatePassword');
|
||||
|
||||
$component
|
||||
->assertHasErrors(['current_password'])
|
||||
->assertNoRedirect();
|
||||
}
|
||||
}
|
||||
36
tests/Feature/Auth/RegistrationTest.php
Normal file
36
tests/Feature/Auth/RegistrationTest.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Volt\Volt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RegistrationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_registration_screen_can_be_rendered(): void
|
||||
{
|
||||
$response = $this->get('/register');
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSeeVolt('pages.auth.register');
|
||||
}
|
||||
|
||||
public function test_new_users_can_register(): void
|
||||
{
|
||||
$component = Volt::test('pages.auth.register')
|
||||
->set('name', 'Test User')
|
||||
->set('email', 'test@example.com')
|
||||
->set('password', 'password')
|
||||
->set('password_confirmation', 'password');
|
||||
|
||||
$component->call('register');
|
||||
|
||||
$component->assertRedirect(route('dashboard', absolute: false));
|
||||
|
||||
$this->assertAuthenticated();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,21 @@
|
||||
<?php
|
||||
|
||||
it('returns a successful response', function () {
|
||||
$response = $this->get('/');
|
||||
namespace Tests\Feature;
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* A basic feature test example.
|
||||
*/
|
||||
public function test_the_application_returns_a_successful_response(): void
|
||||
{
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
}
|
||||
|
||||
179
tests/Feature/ManufacturerTest.php
Normal file
179
tests/Feature/ManufacturerTest.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Manufacturer;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Manufacturer Model Feature Tests
|
||||
*
|
||||
* Tests for ThrillWiki Manufacturer model functionality
|
||||
*/
|
||||
class ManufacturerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
/**
|
||||
* Test model creation.
|
||||
*/
|
||||
public function test_can_create_manufacturer(): void
|
||||
{
|
||||
$manufacturer = Manufacturer::factory()->create();
|
||||
|
||||
$this->assertDatabaseHas('manufacturers', [
|
||||
'id' => $manufacturer->id,
|
||||
'name' => $manufacturer->name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test model factory.
|
||||
*/
|
||||
public function test_manufacturer_factory_works(): void
|
||||
{
|
||||
$manufacturer = Manufacturer::factory()->create();
|
||||
|
||||
$this->assertInstanceOf(Manufacturer::class, $manufacturer);
|
||||
$this->assertNotEmpty($manufacturer->name);
|
||||
$this->assertIsBool($manufacturer->is_active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test active scope.
|
||||
*/
|
||||
public function test_active_scope_filters_correctly(): void
|
||||
{
|
||||
Manufacturer::factory()->active()->create();
|
||||
Manufacturer::factory()->inactive()->create();
|
||||
|
||||
$activeCount = Manufacturer::active()->count();
|
||||
$totalCount = Manufacturer::count();
|
||||
|
||||
$this->assertEquals(1, $activeCount);
|
||||
$this->assertEquals(2, $totalCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test major manufacturers scope.
|
||||
*/
|
||||
public function test_major_manufacturers_scope(): void
|
||||
{
|
||||
// Create manufacturers with different ride counts
|
||||
Manufacturer::factory()->create(['total_rides' => 10]);
|
||||
Manufacturer::factory()->create(['total_rides' => 3]);
|
||||
Manufacturer::factory()->create(['total_rides' => 8]);
|
||||
|
||||
$majorManufacturers = Manufacturer::majorManufacturers()->get();
|
||||
$this->assertEquals(2, $majorManufacturers->count());
|
||||
|
||||
// Test custom minimum
|
||||
$majorManufacturers = Manufacturer::majorManufacturers(8)->get();
|
||||
$this->assertEquals(2, $majorManufacturers->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test coaster manufacturers scope.
|
||||
*/
|
||||
public function test_coaster_manufacturers_scope(): void
|
||||
{
|
||||
Manufacturer::factory()->create(['total_roller_coasters' => 5]);
|
||||
Manufacturer::factory()->create(['total_roller_coasters' => 0]);
|
||||
|
||||
$coasterManufacturers = Manufacturer::coasterManufacturers()->get();
|
||||
$this->assertEquals(1, $coasterManufacturers->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test optimized scope.
|
||||
*/
|
||||
public function test_optimized_scope(): void
|
||||
{
|
||||
$manufacturer = Manufacturer::factory()->create();
|
||||
|
||||
$optimized = Manufacturer::optimized()->first();
|
||||
$this->assertInstanceOf(Manufacturer::class, $optimized);
|
||||
$this->assertEquals($manufacturer->id, $optimized->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test display name attribute.
|
||||
*/
|
||||
public function test_display_name_attribute(): void
|
||||
{
|
||||
$manufacturer = Manufacturer::factory()->create([
|
||||
'name' => 'Intamin AG',
|
||||
'total_rides' => 15
|
||||
]);
|
||||
|
||||
$this->assertEquals('Intamin AG (15 rides)', $manufacturer->display_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test website URL attribute.
|
||||
*/
|
||||
public function test_website_url_attribute(): void
|
||||
{
|
||||
// Test with https URL
|
||||
$manufacturer1 = Manufacturer::factory()->create(['website' => 'https://intamin.com']);
|
||||
$this->assertEquals('https://intamin.com', $manufacturer1->website_url);
|
||||
|
||||
// Test with http URL
|
||||
$manufacturer2 = Manufacturer::factory()->create(['website' => 'http://intamin.com']);
|
||||
$this->assertEquals('http://intamin.com', $manufacturer2->website_url);
|
||||
|
||||
// Test without protocol
|
||||
$manufacturer3 = Manufacturer::factory()->create(['website' => 'intamin.com']);
|
||||
$this->assertEquals('https://intamin.com', $manufacturer3->website_url);
|
||||
|
||||
// Test empty website
|
||||
$manufacturer4 = Manufacturer::factory()->create(['website' => null]);
|
||||
$this->assertEquals('', $manufacturer4->website_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update statistics method.
|
||||
*/
|
||||
public function test_update_statistics(): void
|
||||
{
|
||||
$manufacturer = Manufacturer::factory()->create([
|
||||
'total_rides' => 0,
|
||||
'total_roller_coasters' => 0
|
||||
]);
|
||||
|
||||
// This test assumes Ride model exists and has proper relationship
|
||||
// For now, we'll just test that the method exists and doesn't error
|
||||
$manufacturer->updateStatistics();
|
||||
|
||||
// Verify the method completes without error
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route key name.
|
||||
*/
|
||||
public function test_route_key_name(): void
|
||||
{
|
||||
$manufacturer = new Manufacturer();
|
||||
$this->assertEquals('slug', $manufacturer->getRouteKeyName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test soft deletes.
|
||||
*/
|
||||
public function test_soft_deletes_work(): void
|
||||
{
|
||||
$manufacturer = Manufacturer::factory()->create();
|
||||
$manufacturer->delete();
|
||||
|
||||
$this->assertSoftDeleted($manufacturer);
|
||||
|
||||
// Test that it's excluded from normal queries
|
||||
$this->assertEquals(0, Manufacturer::count());
|
||||
|
||||
// Test that it's included in withTrashed queries
|
||||
$this->assertEquals(1, Manufacturer::withTrashed()->count());
|
||||
}
|
||||
}
|
||||
106
tests/Feature/OperatorControllerTest.php
Normal file
106
tests/Feature/OperatorControllerTest.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Operator;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class OperatorControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected User $user;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->user = User::factory()->create();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_display_operators_index(): void
|
||||
{
|
||||
Operator::factory()->count(3)->create();
|
||||
|
||||
$response = $this->actingAs($this->user)->get(route('operators.index'));
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertSee('Operators');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_create_a_operator(): void
|
||||
{
|
||||
$operatorData = [
|
||||
'name' => 'Test Operator',
|
||||
'description' => 'Test description',
|
||||
'is_active' => true,
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)->post(route('operators.store'), $operatorData);
|
||||
|
||||
$response->assertRedirect();
|
||||
$this->assertDatabaseHas('operators', $operatorData);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_show_a_operator(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
|
||||
$response = $this->actingAs($this->user)->get(route('operators.show', $operator));
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertSee($operator->name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_update_a_operator(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
$updateData = [
|
||||
'name' => 'Updated Operator',
|
||||
'description' => 'Updated description',
|
||||
'is_active' => false,
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)->put(route('operators.update', $operator), $updateData);
|
||||
|
||||
$response->assertRedirect();
|
||||
$this->assertDatabaseHas('operators', $updateData);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_delete_a_operator(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
|
||||
$response = $this->actingAs($this->user)->delete(route('operators.destroy', $operator));
|
||||
|
||||
$response->assertRedirect();
|
||||
$this->assertSoftDeleted('operators', ['id' => $operator->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_validates_required_fields(): void
|
||||
{
|
||||
$response = $this->actingAs($this->user)->post(route('operators.store'), []);
|
||||
|
||||
$response->assertSessionHasErrors(['name']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_search_operators(): void
|
||||
{
|
||||
$operator1 = Operator::factory()->create(['name' => 'Searchable Operator']);
|
||||
$operator2 = Operator::factory()->create(['name' => 'Other Operator']);
|
||||
|
||||
$response = $this->actingAs($this->user)->get(route('operators.index', ['search' => 'Searchable']));
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertSee($operator1->name)
|
||||
->assertDontSee($operator2->name);
|
||||
}
|
||||
}
|
||||
101
tests/Feature/OperatorTest.php
Normal file
101
tests/Feature/OperatorTest.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Operator;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Operator Model Feature Tests
|
||||
*
|
||||
* Tests for ThrillWiki Operator model functionality
|
||||
*/
|
||||
class OperatorTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
/**
|
||||
* Test model creation.
|
||||
*/
|
||||
public function test_can_create_operator(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
|
||||
$this->assertDatabaseHas('operators', [
|
||||
'id' => $operator->id,
|
||||
'name' => $operator->name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test model factory.
|
||||
*/
|
||||
public function test_operator_factory_works(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
|
||||
$this->assertInstanceOf(Operator::class, $operator);
|
||||
$this->assertNotEmpty($operator->name);
|
||||
$this->assertIsBool($operator->is_active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test active scope.
|
||||
*/
|
||||
public function test_active_scope_filters_correctly(): void
|
||||
{
|
||||
Operator::factory()->active()->create();
|
||||
Operator::factory()->inactive()->create();
|
||||
|
||||
$activeCount = Operator::active()->count();
|
||||
$totalCount = Operator::count();
|
||||
|
||||
$this->assertEquals(1, $activeCount);
|
||||
$this->assertEquals(2, $totalCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache key generation.
|
||||
*/
|
||||
public function test_cache_key_generation(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
|
||||
$cacheKey = $operator->getCacheKey();
|
||||
$expectedKey = strtolower('operator') . '.' . $operator->id;
|
||||
|
||||
$this->assertEquals($expectedKey, $cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache key with suffix.
|
||||
*/
|
||||
public function test_cache_key_with_suffix(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
|
||||
$cacheKey = $operator->getCacheKey('details');
|
||||
$expectedKey = strtolower('operator') . '.' . $operator->id . '.details';
|
||||
|
||||
$this->assertEquals($expectedKey, $cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test soft deletes.
|
||||
*/
|
||||
public function test_soft_deletes_work(): void
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
$operator->delete();
|
||||
|
||||
$this->assertSoftDeleted($operator);
|
||||
|
||||
// Test that it's excluded from normal queries
|
||||
$this->assertEquals(0, Operator::count());
|
||||
|
||||
// Test that it's included in withTrashed queries
|
||||
$this->assertEquals(1, Operator::withTrashed()->count());
|
||||
}
|
||||
}
|
||||
101
tests/Feature/ProfileTest.php
Normal file
101
tests/Feature/ProfileTest.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Volt\Volt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ProfileTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_profile_page_is_displayed(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/profile');
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSeeVolt('profile.update-profile-information-form')
|
||||
->assertSeeVolt('profile.update-password-form')
|
||||
->assertSeeVolt('profile.delete-user-form');
|
||||
}
|
||||
|
||||
public function test_profile_information_can_be_updated(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('profile.update-profile-information-form')
|
||||
->set('name', 'Test User')
|
||||
->set('email', 'test@example.com')
|
||||
->call('updateProfileInformation');
|
||||
|
||||
$component
|
||||
->assertHasNoErrors()
|
||||
->assertNoRedirect();
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertSame('Test User', $user->name);
|
||||
$this->assertSame('test@example.com', $user->email);
|
||||
$this->assertNull($user->email_verified_at);
|
||||
}
|
||||
|
||||
public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('profile.update-profile-information-form')
|
||||
->set('name', 'Test User')
|
||||
->set('email', $user->email)
|
||||
->call('updateProfileInformation');
|
||||
|
||||
$component
|
||||
->assertHasNoErrors()
|
||||
->assertNoRedirect();
|
||||
|
||||
$this->assertNotNull($user->refresh()->email_verified_at);
|
||||
}
|
||||
|
||||
public function test_user_can_delete_their_account(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('profile.delete-user-form')
|
||||
->set('password', 'password')
|
||||
->call('deleteUser');
|
||||
|
||||
$component
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertGuest();
|
||||
$this->assertNull($user->fresh());
|
||||
}
|
||||
|
||||
public function test_correct_password_must_be_provided_to_delete_account(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$component = Volt::test('profile.delete-user-form')
|
||||
->set('password', 'wrong-password')
|
||||
->call('deleteUser');
|
||||
|
||||
$component
|
||||
->assertHasErrors('password')
|
||||
->assertNoRedirect();
|
||||
|
||||
$this->assertNotNull($user->fresh());
|
||||
}
|
||||
}
|
||||
106
tests/Feature/RideControllerTest.php
Normal file
106
tests/Feature/RideControllerTest.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Ride;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RideControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected User $user;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->user = User::factory()->create();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_display_rides_index(): void
|
||||
{
|
||||
Ride::factory()->count(3)->create();
|
||||
|
||||
$response = $this->actingAs($this->user)->get(route('rides.index'));
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertSee('Rides');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_create_a_ride(): void
|
||||
{
|
||||
$rideData = [
|
||||
'name' => 'Test Ride',
|
||||
'description' => 'Test description',
|
||||
'is_active' => true,
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)->post(route('rides.store'), $rideData);
|
||||
|
||||
$response->assertRedirect();
|
||||
$this->assertDatabaseHas('rides', $rideData);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_show_a_ride(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
|
||||
$response = $this->actingAs($this->user)->get(route('rides.show', $ride));
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertSee($ride->name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_update_a_ride(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
$updateData = [
|
||||
'name' => 'Updated Ride',
|
||||
'description' => 'Updated description',
|
||||
'is_active' => false,
|
||||
];
|
||||
|
||||
$response = $this->actingAs($this->user)->put(route('rides.update', $ride), $updateData);
|
||||
|
||||
$response->assertRedirect();
|
||||
$this->assertDatabaseHas('rides', $updateData);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_delete_a_ride(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
|
||||
$response = $this->actingAs($this->user)->delete(route('rides.destroy', $ride));
|
||||
|
||||
$response->assertRedirect();
|
||||
$this->assertSoftDeleted('rides', ['id' => $ride->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_validates_required_fields(): void
|
||||
{
|
||||
$response = $this->actingAs($this->user)->post(route('rides.store'), []);
|
||||
|
||||
$response->assertSessionHasErrors(['name']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_search_rides(): void
|
||||
{
|
||||
$ride1 = Ride::factory()->create(['name' => 'Searchable Ride']);
|
||||
$ride2 = Ride::factory()->create(['name' => 'Other Ride']);
|
||||
|
||||
$response = $this->actingAs($this->user)->get(route('rides.index', ['search' => 'Searchable']));
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertSee($ride1->name)
|
||||
->assertDontSee($ride2->name);
|
||||
}
|
||||
}
|
||||
101
tests/Feature/RideTest.php
Normal file
101
tests/Feature/RideTest.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Ride;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Ride Model Feature Tests
|
||||
*
|
||||
* Tests for ThrillWiki Ride model functionality
|
||||
*/
|
||||
class RideTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
/**
|
||||
* Test model creation.
|
||||
*/
|
||||
public function test_can_create_ride(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
|
||||
$this->assertDatabaseHas('rides', [
|
||||
'id' => $ride->id,
|
||||
'name' => $ride->name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test model factory.
|
||||
*/
|
||||
public function test_ride_factory_works(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
|
||||
$this->assertInstanceOf(Ride::class, $ride);
|
||||
$this->assertNotEmpty($ride->name);
|
||||
$this->assertIsBool($ride->is_active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test active scope.
|
||||
*/
|
||||
public function test_active_scope_filters_correctly(): void
|
||||
{
|
||||
Ride::factory()->active()->create();
|
||||
Ride::factory()->inactive()->create();
|
||||
|
||||
$activeCount = Ride::active()->count();
|
||||
$totalCount = Ride::count();
|
||||
|
||||
$this->assertEquals(1, $activeCount);
|
||||
$this->assertEquals(2, $totalCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache key generation.
|
||||
*/
|
||||
public function test_cache_key_generation(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
|
||||
$cacheKey = $ride->getCacheKey();
|
||||
$expectedKey = strtolower('ride') . '.' . $ride->id;
|
||||
|
||||
$this->assertEquals($expectedKey, $cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache key with suffix.
|
||||
*/
|
||||
public function test_cache_key_with_suffix(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
|
||||
$cacheKey = $ride->getCacheKey('details');
|
||||
$expectedKey = strtolower('ride') . '.' . $ride->id . '.details';
|
||||
|
||||
$this->assertEquals($expectedKey, $cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test soft deletes.
|
||||
*/
|
||||
public function test_soft_deletes_work(): void
|
||||
{
|
||||
$ride = Ride::factory()->create();
|
||||
$ride->delete();
|
||||
|
||||
$this->assertSoftDeleted($ride);
|
||||
|
||||
// Test that it's excluded from normal queries
|
||||
$this->assertEquals(0, Ride::count());
|
||||
|
||||
// Test that it's included in withTrashed queries
|
||||
$this->assertEquals(1, Ride::withTrashed()->count());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,16 @@
|
||||
<?php
|
||||
|
||||
test('that true is true', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
namespace Tests\Unit;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic test example.
|
||||
*/
|
||||
public function test_that_true_is_true(): void
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user