create(); $response = $this ->actingAs($user) ->get(route('app.profile.edit')); $response->assertOk(); }); test('profile information can be updated', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->put(route('app.profile.update'), [ 'name' => 'Test User', 'email' => 'test@example.com', ]); $response ->assertSessionHasNoErrors() ->assertRedirect(route('app.profile.edit')); $user->refresh(); expect($user->name)->toBe('Test User'); expect($user->email)->toBe('test@example.com'); expect($user->email_verified_at)->toBeNull(); }); test('email verification status is unchanged when the email address is unchanged', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->put(route('app.profile.update'), [ 'name' => 'Test User', 'email' => $user->email, ]); $response ->assertSessionHasNoErrors() ->assertRedirect(route('app.profile.edit')); expect($user->refresh()->email_verified_at)->not->toBeNull(); }); test('user can update their locale via cookie', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->from(route('app.posts.index')) ->put(route('app.profile.language'), [ 'locale' => 'es', ]); $response ->assertSessionHasNoErrors() ->assertRedirect(route('app.posts.index')); $response->assertCookieNotExpired('locale'); }); test('user cannot update locale with invalid code', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->put(route('app.profile.language'), [ 'locale' => 'invalid', ]); $response->assertSessionHasErrors('locale'); }); test('user can delete their account', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->delete(route('app.profile.destroy'), [ 'password' => 'password', ]); $response ->assertSessionHasNoErrors() ->assertRedirect(route('app.home')); $this->assertGuest(); expect($user->fresh())->toBeNull(); }); test('correct password must be provided to delete account', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->from(route('app.profile.edit')) ->delete(route('app.profile.destroy'), [ 'password' => 'wrong-password', ]); $response ->assertSessionHasErrors('password') ->assertRedirect(route('app.profile.edit')); expect($user->fresh())->not->toBeNull(); }); test('deleting account updates members current_workspace_id when their workspace is deleted', function () { $owner = User::factory()->create(); $member = User::factory()->create(); // Create a workspace owned by the owner $workspace = Workspace::factory()->create(['user_id' => $owner->id]); $owner->workspaces()->attach($workspace->id, ['role' => Role::Owner->value]); $owner->update(['current_workspace_id' => $workspace->id]); // Add member to the workspace and set it as their current $member->workspaces()->attach($workspace->id, ['role' => Role::Member->value]); $member->update(['current_workspace_id' => $workspace->id]); // Verify setup expect($member->current_workspace_id)->toBe($workspace->id); // Owner deletes their account $this ->actingAs($owner) ->delete(route('app.profile.destroy'), [ 'password' => 'password', ]); // Verify member's current_workspace_id is updated to null (since they have no other workspace) expect($member->fresh()->current_workspace_id)->toBeNull(); }); test('deleting account updates members current_workspace_id to another workspace when available', function () { $owner = User::factory()->create(); $member = User::factory()->create(); $otherOwner = User::factory()->create(); // Create workspace owned by the owner being deleted $workspaceToDelete = Workspace::factory()->create(['user_id' => $owner->id]); $owner->workspaces()->attach($workspaceToDelete->id, ['role' => Role::Owner->value]); $owner->update(['current_workspace_id' => $workspaceToDelete->id]); // Create another workspace owned by a different user $otherWorkspace = Workspace::factory()->create(['user_id' => $otherOwner->id]); $otherOwner->workspaces()->attach($otherWorkspace->id, ['role' => Role::Owner->value]); // Add member to both workspaces $member->workspaces()->attach($workspaceToDelete->id, ['role' => Role::Member->value]); $member->workspaces()->attach($otherWorkspace->id, ['role' => Role::Member->value]); $member->update(['current_workspace_id' => $workspaceToDelete->id]); // Verify setup expect($member->current_workspace_id)->toBe($workspaceToDelete->id); // Owner deletes their account $this ->actingAs($owner) ->delete(route('app.profile.destroy'), [ 'password' => 'password', ]); // Verify member's current_workspace_id is updated to the other workspace expect($member->fresh()->current_workspace_id)->toBe($otherWorkspace->id); }); test('user can upload profile photo', function () { Storage::fake(); $user = User::factory()->create(); $response = $this ->actingAs($user) ->post(route('app.profile.upload-photo'), [ 'photo' => UploadedFile::fake()->image('avatar.jpg', 200, 200), ]); $response->assertRedirect(); $user->refresh(); expect($user->has_photo)->toBeTrue(); expect($user->photo_url)->not->toBeNull(); }); test('user cannot upload non-image file as photo', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->post(route('app.profile.upload-photo'), [ 'photo' => UploadedFile::fake()->create('document.pdf', 100), ]); $response->assertSessionHasErrors('photo'); }); test('user can delete profile photo', function () { Storage::fake(); $user = User::factory()->create(); // Upload first $this->actingAs($user)->post(route('app.profile.upload-photo'), [ 'photo' => UploadedFile::fake()->image('avatar.jpg', 200, 200), ]); $user->refresh(); expect($user->has_photo)->toBeTrue(); // Delete $response = $this->actingAs($user)->delete(route('app.profile.delete-photo')); $response->assertRedirect(); $user->refresh(); expect($user->has_photo)->toBeFalse(); });