Files
radicall/tests/Feature/Http/Client/AuthControllerTest.php
T

257 lines
10 KiB
PHP

<?php
namespace Tests\Feature\Http\Client;
use App\Enums\UserEnum;
use App\Models\OtpCode;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase;
class AuthControllerTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
Http::fake();
}
public function test_phone_page_renders(): void
{
$this->get(route('login'))->assertOk()->assertInertia(fn (Assert $page) => $page->component('Auth/Phone'));
}
public function test_authenticated_user_is_redirected_away_from_guest_routes(): void
{
$this->actingAs(User::factory()->create())->get(route('login'))->assertRedirect();
}
public function test_check_phone_redirects_to_password_when_phone_has_single_level(): void
{
User::factory()->create(['phone' => '+989120000000', 'level' => UserEnum::Doctor->value]);
$response = $this->post(route('checkPhone'), ['prefix' => '+98', 'phone' => '09120000000']);
$response->assertRedirect(route('password'));
$response->assertSessionHas('login_phone', '+989120000000');
$response->assertSessionHas('login_level', 'doctor');
}
public function test_check_phone_redirects_to_portal_when_phone_has_multiple_levels(): void
{
User::factory()->create(['phone' => '+989120000000', 'level' => UserEnum::Doctor->value]);
User::factory()->create(['phone' => '+989120000000', 'level' => UserEnum::Supervisor->value]);
$response = $this->post(route('checkPhone'), ['prefix' => '+98', 'phone' => '09120000000']);
$response->assertRedirect(route('portal'));
$response->assertSessionHas('available_levels');
}
public function test_check_phone_redirects_to_registration_for_unknown_phone(): void
{
$response = $this->post(route('checkPhone'), ['prefix' => '+98', 'phone' => '09120000000']);
$response->assertRedirect(route('register.chooseType'));
$response->assertSessionHas('register_phone', '+989120000000');
}
public function test_check_phone_validates_input(): void
{
$this->post(route('checkPhone'), ['phone' => 'abc'])->assertSessionHasErrors(['prefix', 'phone']);
}
public function test_choose_portal_requires_session_state(): void
{
$this->get(route('portal'))->assertRedirect(route('login'));
}
public function test_choose_portal_renders_available_levels(): void
{
$this->withSession(['login_phone' => '+989120000000', 'available_levels' => ['doctor', 'supervisor']])
->get(route('portal'))
->assertOk()
->assertInertia(fn (Assert $page) => $page->component('Auth/ChoosePortal')->where('availableLevels', ['doctor', 'supervisor']));
}
public function test_choose_portal_with_level_stores_it_and_redirects_to_password(): void
{
$this->withSession(['login_phone' => '+989120000000', 'available_levels' => ['doctor', 'supervisor']])
->get(route('portal', 'doctor'))
->assertRedirect(route('password'))
->assertSessionHas('login_level', 'doctor');
}
public function test_password_form_requires_session_state(): void
{
$this->get(route('password'))->assertRedirect(route('login'));
}
public function test_password_form_renders(): void
{
$this->withSession(['login_phone' => '+989120000000', 'login_level' => 'doctor'])
->get(route('password'))
->assertOk()
->assertInertia(fn (Assert $page) => $page->component('Auth/Password')->where('level', 'doctor'));
}
public function test_authenticate_logs_in_and_redirects_to_dashboard(): void
{
$user = User::factory()->create(['phone' => '+989120000000', 'level' => UserEnum::Doctor->value, 'password' => 'secret123']);
$this->withSession(['login_phone' => '+989120000000', 'login_level' => 'doctor'])
->post(route('authenticate'), ['password' => 'secret123'])
->assertRedirect(route('dashboard.index'));
$this->assertAuthenticatedAs($user);
}
public function test_authenticate_rejects_wrong_password(): void
{
User::factory()->create(['phone' => '+989120000000', 'level' => UserEnum::Doctor->value, 'password' => 'secret123']);
$this->withSession(['login_phone' => '+989120000000', 'login_level' => 'doctor'])
->from(route('password'))
->post(route('authenticate'), ['password' => 'wrong'])
->assertRedirect(route('password'))
->assertSessionHasErrors('password');
$this->assertGuest();
}
public function test_authenticate_without_session_redirects_to_login(): void
{
$this->post(route('authenticate'), ['password' => 'secret123'])->assertRedirect(route('login'));
}
public function test_send_otp_stores_code_and_redirects_to_verification(): void
{
$this->withSession(['login_phone' => '+989120000000'])
->post(route('sendOtp'))
->assertRedirect(route('otpVerification'));
$this->assertDatabaseHas('otp_codes', ['phone' => '+989120000000']);
}
public function test_send_otp_without_phone_redirects_to_login(): void
{
$this->post(route('sendOtp'))->assertRedirect(route('login'));
$this->assertDatabaseCount('otp_codes', 0);
}
public function test_otp_verification_page_renders_with_phone(): void
{
$this->withSession(['login_phone' => '+989120000000'])
->get(route('otpVerification'))
->assertOk()
->assertInertia(fn (Assert $page) => $page->component('Auth/OtpVerification')->where('phone', '+989120000000'));
}
public function test_verify_otp_marks_session_verified_and_redirects_to_reset(): void
{
OtpCode::factory()->create(['phone' => '+989120000000', 'code' => '1234']);
$this->withSession(['login_phone' => '+989120000000'])
->post(route('verifyOtp'), ['otp_code' => '1234'])
->assertRedirect(route('resetPassword'))
->assertSessionHas('otp_verified', true)
->assertSessionHas('verified_phone', '+989120000000');
$this->assertDatabaseCount('otp_codes', 0);
}
public function test_verify_otp_rejects_invalid_code(): void
{
OtpCode::factory()->create(['phone' => '+989120000000', 'code' => '1234']);
$this->withSession(['login_phone' => '+989120000000'])
->post(route('verifyOtp'), ['otp_code' => '0000'])
->assertSessionHasErrors('otp_code');
}
public function test_reset_password_page_requires_verified_session(): void
{
$this->get(route('resetPassword'))->assertRedirect(route('login'));
$this->withSession(['otp_verified' => true, 'verified_phone' => '+989120000000'])
->get(route('resetPassword'))
->assertOk()
->assertInertia(fn (Assert $page) => $page->component('Auth/ResetPassword'));
}
public function test_update_password_changes_password_and_flushes_session(): void
{
$user = User::factory()->create(['phone' => '+989120000000', 'level' => UserEnum::Doctor->value]);
$this->withSession(['otp_verified' => true, 'verified_phone' => '+989120000000', 'login_level' => 'doctor'])
->post(route('updatePassword'), ['password' => 'newsecret1', 'password_confirmation' => 'newsecret1'])
->assertRedirect(route('login'))
->assertSessionMissing('otp_verified');
$this->assertTrue(Hash::check('newsecret1', $user->fresh()->password));
}
public function test_update_password_validates_confirmation_and_length(): void
{
$this->withSession(['otp_verified' => true, 'verified_phone' => '+989120000000', 'login_level' => 'doctor'])
->post(route('updatePassword'), ['password' => 'short', 'password_confirmation' => 'other'])
->assertSessionHasErrors('password');
}
public function test_update_password_without_verified_session_redirects_to_login(): void
{
$this->post(route('updatePassword'), ['password' => 'newsecret1', 'password_confirmation' => 'newsecret1'])
->assertRedirect(route('login'));
}
public function test_update_password_for_unknown_user_redirects_to_login_with_error(): void
{
$this->withSession(['otp_verified' => true, 'verified_phone' => '+989120000000', 'login_level' => 'doctor'])
->post(route('updatePassword'), ['password' => 'newsecret1', 'password_confirmation' => 'newsecret1'])
->assertRedirect(route('login'))
->assertSessionHas('error');
}
public function test_register_pages_render_with_session_phone(): void
{
$session = ['register_phone' => '+989120000000'];
$this->withSession($session)->get(route('register.chooseType'))->assertInertia(fn (Assert $page) => $page->component('Auth/ChooseRegisterType')->where('phone', '+989120000000'));
$this->withSession($session)->get(route('register.supervisor'))->assertInertia(fn (Assert $page) => $page->component('Auth/RegisterSupervisor'));
$this->withSession($session)->get(route('register.veterinarian'))->assertInertia(fn (Assert $page) => $page->component('Auth/RegisterVet'));
}
public function test_store_registers_user_with_session_phone_and_logs_in(): void
{
$this->withSession(['register_phone' => '+989120000000'])
->post(route('register.store'), ['phone' => '09999999999', 'national_code' => '0012345678', 'level' => UserEnum::Vet->value])
->assertRedirect(route('dashboard.index'));
$this->assertAuthenticated();
$this->assertDatabaseHas('users', ['phone' => '+989120000000', 'national_code' => '0012345678']);
$this->assertDatabaseMissing('users', ['phone' => '09999999999']);
}
public function test_store_without_session_phone_redirects_to_login(): void
{
$this->post(route('register.store'), ['phone' => '09120000000', 'national_code' => '0012345678'])
->assertRedirect(route('login'));
$this->assertGuest();
$this->assertDatabaseCount('users', 0);
}
public function test_logout_ends_session(): void
{
$this->actingAs(User::factory()->create())->get(route('dashboard.logout'))->assertRedirect(route('login'));
$this->assertGuest();
}
}