From 347aa0aef5b2ce3cbc13962db476e47c378a6ee5 Mon Sep 17 00:00:00 2001 From: Javier Feliz Date: Sat, 2 Aug 2025 19:15:04 -0400 Subject: [PATCH] More testing --- tests/Feature/Auth/RegistrationTest.php | 170 +++++++++++++- tests/Feature/Forms/UserProfileTest.php | 298 ++++++++++++++++++++++++ 2 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/Forms/UserProfileTest.php diff --git a/tests/Feature/Auth/RegistrationTest.php b/tests/Feature/Auth/RegistrationTest.php index fea78a3..20193b2 100644 --- a/tests/Feature/Auth/RegistrationTest.php +++ b/tests/Feature/Auth/RegistrationTest.php @@ -1,6 +1,8 @@ assertRedirect(route('dashboard', absolute: false)); $this->assertAuthenticated(); -}); \ No newline at end of file +}); + +test('registration without invitation code shows invitation required message', function () { + $component = Livewire::test(Register::class); + + $component->assertSee('Invitation Required'); + $component->assertSee('An invitation is required to create an account'); + $component->assertSee('Registration is by invitation only'); + $component->assertSee('Return to login'); +}); + +test('registration with valid invitation code shows registration form', function () { + $invitation = Invitation::factory()->create([ + 'email' => 'invited@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]); + + $component->assertSee('Create an account'); + $component->assertSee('Enter your details below to create your account'); + $component->assertSet('email', 'invited@example.com'); + $component->assertSet('invitation.email', 'invited@example.com'); +}); + +test('user can register with valid invitation code', function () { + $invitation = Invitation::factory()->create([ + 'email' => 'invited@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]) + ->set('name', 'Invited User') + ->set('email', 'invited@example.com') + ->set('password', 'password123') + ->set('password_confirmation', 'password123') + ->call('register'); + + $component + ->assertHasNoErrors() + ->assertRedirect(route('dashboard', absolute: false)); + + $this->assertAuthenticated(); + + // Verify invitation was accepted + $invitation->refresh(); + expect($invitation->accepted_at)->not->toBeNull(); + expect($invitation->isPending())->toBeFalse(); + + // Verify user was created with correct email + $user = User::where('email', 'invited@example.com')->first(); + expect($user)->not->toBeNull(); + expect($user->name)->toBe('Invited User'); +}); + +test('registration with non-existent invitation code shows invalid invitation message', function () { + $component = Livewire::test(Register::class, ['code' => 'non-existent-code']); + + $component->assertSee('Invalid Invitation'); + $component->assertSee('This invitation link is not valid'); + $component->assertSee('The invitation link you used is invalid or has expired'); + $component->assertSee('Return to login'); + $component->assertSet('invitation', null); +}); + +test('registration with already accepted invitation shows invitation already used message', function () { + $invitation = Invitation::factory()->accepted()->create([ + 'email' => 'already-used@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]); + + $component->assertSee('Invitation Already Used'); + $component->assertSee('This invitation has already been accepted'); + $component->assertSee('This invitation code has already been used'); + $component->assertSee('Return to login'); + $component->assertSet('invitationAccepted', true); +}); + +test('cannot register with already accepted invitation', function () { + $invitation = Invitation::factory()->accepted()->create([ + 'email' => 'already-used@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]) + ->set('name', 'Test User') + ->set('email', 'already-used@example.com') + ->set('password', 'password123') + ->set('password_confirmation', 'password123') + ->call('register'); + + $component->assertHasErrors(['general' => 'This invitation has already been accepted.']); + $this->assertGuest(); +}); + +test('email field is disabled when using invitation code', function () { + $invitation = Invitation::factory()->create([ + 'email' => 'invited@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]); + + // Check that email is pre-filled and component knows invitation exists + $component->assertSet('email', 'invited@example.com'); + $component->assertSet('invitation.email', 'invited@example.com'); +}); + +test('cannot register with different email than invitation email', function () { + $invitation = Invitation::factory()->create([ + 'email' => 'invited@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]) + ->set('name', 'Test User') + ->set('email', 'different@example.com') + ->set('password', 'password123') + ->set('password_confirmation', 'password123') + ->call('register'); + + $component->assertHasErrors(['email']); + $this->assertGuest(); +}); + +test('registration requires all required fields', function () { + $invitation = Invitation::factory()->create([ + 'email' => 'invited@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]) + ->set('name', '') + ->set('email', 'invited@example.com') + ->set('password', '') + ->set('password_confirmation', '') + ->call('register'); + + $component->assertHasErrors(['name', 'password']); + $this->assertGuest(); +}); + +test('registration requires password confirmation', function () { + $invitation = Invitation::factory()->create([ + 'email' => 'invited@example.com' + ]); + + $component = Livewire::test(Register::class, ['code' => $invitation->code]) + ->set('name', 'Test User') + ->set('email', 'invited@example.com') + ->set('password', 'password123') + ->set('password_confirmation', 'different-password') + ->call('register'); + + $component->assertHasErrors(['password']); + $this->assertGuest(); +}); + +test('registration without invitation requires unique email', function () { + // Create an existing user + User::factory()->create(['email' => 'existing@example.com']); + + $component = Livewire::test(Register::class) + ->set('name', 'Test User') + ->set('email', 'existing@example.com') + ->set('password', 'password123') + ->set('password_confirmation', 'password123') + ->call('register'); + + $component->assertHasErrors(['email']); + $this->assertGuest(); +}); diff --git a/tests/Feature/Forms/UserProfileTest.php b/tests/Feature/Forms/UserProfileTest.php new file mode 100644 index 0000000..b0127d8 --- /dev/null +++ b/tests/Feature/Forms/UserProfileTest.php @@ -0,0 +1,298 @@ +create([ + 'name' => 'John Doe', + 'email' => 'john@example.com', + 'preferred_username' => 'johndoe', + 'avatar' => 'avatar.jpg', + 'auto_approve_apps' => true, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class); + + expect($component->get('name'))->toBe('John Doe'); + expect($component->get('email'))->toBe('john@example.com'); + expect($component->get('preferred_username'))->toBe('johndoe'); + expect($component->get('avatar'))->toBe('avatar.jpg'); + expect($component->get('auto_approve_apps'))->toBe(true); +}); + +test('profile information can be updated', function () { + $user = User::factory()->create([ + 'name' => 'Old Name', + 'email' => 'old@example.com', + 'preferred_username' => 'olduser', + 'auto_approve_apps' => false, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('name', 'New Name') + ->set('email', 'new@example.com') + ->set('preferred_username', 'newuser') + ->set('auto_approve_apps', true) + ->call('updateProfileInformation'); + + $component->assertHasNoErrors(); + $component->assertDispatched('profile-updated', name: 'New Name'); + + $user->refresh(); + expect($user->name)->toBe('New Name'); + expect($user->email)->toBe('new@example.com'); + expect($user->preferred_username)->toBe('newuser'); + expect($user->auto_approve_apps)->toBe(true); +}); + +test('profile information validation works', function () { + $user = User::factory()->create(['auto_approve_apps' => false]); + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('name', '') + ->set('email', 'invalid-email') + ->call('updateProfileInformation'); + + $component->assertHasErrors(['name', 'email']); +}); + +test('email must be unique when updating profile', function () { + $existingUser = User::factory()->create(['email' => 'existing@example.com', 'auto_approve_apps' => false]); + $user = User::factory()->create(['email' => 'user@example.com', 'auto_approve_apps' => false]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('email', 'existing@example.com') + ->call('updateProfileInformation'); + + $component->assertHasErrors(['email']); +}); + +test('user can keep same email when updating other fields', function () { + $user = User::factory()->create(['email' => 'user@example.com', 'auto_approve_apps' => false]); + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('name', 'Updated Name') + ->set('email', 'user@example.com') + ->set('preferred_username', 'testuser') + ->call('updateProfileInformation'); + + $component->assertHasNoErrors(); +}); + +test('avatar can be uploaded', function () { + Storage::fake('avatars'); + + $user = User::factory()->create(['auto_approve_apps' => false]); + $this->actingAs($user); + + $file = UploadedFile::fake()->create('avatar.jpg', 1000, 'image/jpeg'); + + $component = Livewire::test(UserProfile::class) + ->set('name', 'Test User') + ->set('email', 'test@example.com') + ->set('preferred_username', 'testuser') + ->set('avatarUpload', $file) + ->call('updateProfileInformation'); + + $component->assertHasNoErrors(); + + $user->refresh(); + expect($user->avatar)->not->toBeNull(); + Storage::disk('avatars')->assertExists($user->avatar); +}); + +test('old avatar is deleted when new one is uploaded', function () { + Storage::fake('avatars'); + + $oldAvatarPath = 'old-avatar.jpg'; + Storage::disk('avatars')->put($oldAvatarPath, 'fake content'); + + $user = User::factory()->create(['avatar' => $oldAvatarPath, 'auto_approve_apps' => false]); + $this->actingAs($user); + + $newFile = UploadedFile::fake()->create('new-avatar.jpg', 1000, 'image/jpeg'); + + $component = Livewire::test(UserProfile::class) + ->set('name', 'Test User') + ->set('email', 'test@example.com') + ->set('preferred_username', 'testuser') + ->set('avatarUpload', $newFile) + ->call('updateProfileInformation'); + + $component->assertHasNoErrors(); + + Storage::disk('avatars')->assertMissing($oldAvatarPath); + $user->refresh(); + Storage::disk('avatars')->assertExists($user->avatar); +}); + +test('avatar upload validation works', function () { + $user = User::factory()->create(['auto_approve_apps' => false]); + $this->actingAs($user); + + $file = UploadedFile::fake()->create('document.pdf', 15000); // Too large + + $component = Livewire::test(UserProfile::class) + ->set('avatarUpload', $file); + + $component->assertHasErrors(['avatarUpload']); +}); + +test('password can be updated', function () { + $user = User::factory()->create([ + 'password' => Hash::make('current-password'), + 'auto_approve_apps' => false, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('current_password', 'current-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + $component->assertHasNoErrors(); + $component->assertDispatched('password-updated'); + + expect(Hash::check('new-password', $user->refresh()->password))->toBeTrue(); +}); + +test('current password must be correct to update password', function () { + $user = User::factory()->create([ + 'password' => Hash::make('current-password'), + 'auto_approve_apps' => false, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('current_password', 'wrong-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + $component->assertHasErrors(['current_password']); +}); + +test('new password must be confirmed', function () { + $user = User::factory()->create([ + 'password' => Hash::make('current-password'), + 'auto_approve_apps' => false, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('current_password', 'current-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'different-password') + ->call('updatePassword'); + + $component->assertHasErrors(['password']); +}); + +test('password fields are reset after validation error', function () { + $user = User::factory()->create([ + 'password' => Hash::make('current-password'), + 'auto_approve_apps' => false, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('current_password', 'wrong-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + expect($component->get('current_password'))->toBe(''); + expect($component->get('password'))->toBe(''); + expect($component->get('password_confirmation'))->toBe(''); +}); + +test('password fields are reset after successful update', function () { + $user = User::factory()->create([ + 'password' => Hash::make('current-password'), + 'auto_approve_apps' => false, + ]); + + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('current_password', 'current-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + expect($component->get('current_password'))->toBe(''); + expect($component->get('password'))->toBe(''); + expect($component->get('password_confirmation'))->toBe(''); +}); + +test('component renders correctly', function () { + $user = User::factory()->create(['auto_approve_apps' => false]); + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class); + + $component->assertViewIs('livewire.forms.user-profile'); +}); + +test('profile information form validation requires all required fields', function () { + $user = User::factory()->create(['auto_approve_apps' => false]); + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('name', '') + ->set('email', '') + ->call('updateProfileInformation'); + + $component->assertHasErrors(['name', 'email']); +}); + +test('email validation requires lowercase', function () { + $user = User::factory()->create(['email' => 'original@example.com', 'auto_approve_apps' => false]); + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('name', 'Test User') + ->set('email', 'UPPERCASE@EXAMPLE.COM') + ->set('preferred_username', 'testuser') + ->call('updateProfileInformation'); + + $component->assertHasErrors(['email']); +}); + +test('preferred username can be null', function () { + $user = User::factory()->create(['preferred_username' => 'oldusername', 'auto_approve_apps' => false]); + $this->actingAs($user); + + $component = Livewire::test(UserProfile::class) + ->set('name', 'Test User') + ->set('email', 'test@example.com') + ->set('preferred_username', '') + ->call('updateProfileInformation'); + + $component->assertHasNoErrors(); + + $user->refresh(); + expect($user->preferred_username)->toBe(''); + expect($user->name)->toBe('Test User'); + expect($user->email)->toBe('test@example.com'); +}); \ No newline at end of file