get(route('booking')) ->assertOk() ->assertSee(__('booking.request_consultation')); }); test('logged in user is redirected to client booking', function () { $user = User::factory()->client()->create(); $this->actingAs($user) ->get(route('booking')) ->assertRedirect(route('client.consultations.book')); }); test('guest booking page shows calendar', function () { $this->get(route('booking')) ->assertOk() ->assertSee(__('booking.guest_intro')); }); test('guest can select a slot and see contact form', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); $date = now()->addDay()->format('Y-m-d'); Volt::test('pages.booking') ->call('selectSlot', $date, '09:00') ->assertSet('selectedDate', $date) ->assertSet('selectedTime', '09:00') ->assertSee(__('booking.guest_name')); }); test('guest can submit booking request', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); $date = now()->addDay()->format('Y-m-d'); $component = Volt::test('pages.booking') ->call('selectSlot', $date, '09:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'john@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'I need legal advice regarding a contract dispute with my employer.') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->assertSet('showConfirmation', true) ->call('submit') ->assertRedirect(route('booking.success')); $this->assertDatabaseHas('consultations', [ 'guest_email' => 'john@example.com', 'guest_name' => 'John Doe', 'user_id' => null, 'status' => ConsultationStatus::Pending->value, ]); }); test('guest cannot book twice on same day', function () { $date = now()->addDay()->format('Y-m-d'); WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); // Create existing booking for this email Consultation::factory()->guest()->create([ 'guest_email' => 'john@example.com', 'booking_date' => $date, 'status' => ConsultationStatus::Pending, ]); Volt::test('pages.booking') ->call('selectSlot', $date, '10:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'john@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'Another consultation request for testing purposes.') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->assertHasErrors(['guestEmail']); }); test('invalid captcha prevents submission', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); Volt::test('pages.booking') ->call('selectSlot', now()->addDay()->format('Y-m-d'), '09:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'john@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'I need legal advice regarding a contract dispute.') ->set('captchaAnswer', 'wrong-answer') ->call('showConfirm') ->assertHasErrors(['captchaAnswer']); }); test('rate limiting prevents excessive booking attempts', function () { $ipKey = 'guest-booking:127.0.0.1'; // Exhaust the rate limit (5 attempts) for ($i = 0; $i < 5; $i++) { RateLimiter::hit($ipKey, 60 * 60 * 24); } WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); $date = now()->addDay()->format('Y-m-d'); Volt::test('pages.booking') ->call('selectSlot', $date, '09:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'john@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'I need legal advice regarding a contract dispute with my employer.') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->call('submit') ->assertHasErrors(['guestEmail']); RateLimiter::clear($ipKey); }); test('slot taken during submission shows error', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); $date = now()->addDay()->format('Y-m-d'); // Start the booking process $component = Volt::test('pages.booking') ->call('selectSlot', $date, '09:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'john@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'I need legal advice regarding a contract dispute with my employer.') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->assertSet('showConfirmation', true); // Simulate another booking taking the slot before submission Consultation::factory()->guest()->create([ 'booking_date' => $date, 'booking_time' => '09:00', 'status' => ConsultationStatus::Pending, ]); // Try to submit - should fail with slot taken error $component->call('submit') ->assertHasErrors(['selectedTime']); }); test('guest can clear slot selection', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); $date = now()->addDay()->format('Y-m-d'); Volt::test('pages.booking') ->call('selectSlot', $date, '09:00') ->assertSet('selectedDate', $date) ->call('clearSelection') ->assertSet('selectedDate', null) ->assertSet('selectedTime', null); }); test('guest can refresh captcha', function () { $component = Volt::test('pages.booking'); $firstQuestion = $component->get('captchaQuestion'); $component->call('refreshCaptcha'); // Just verify the captcha answer was reset $component->assertSet('captchaAnswer', ''); }); test('success page is accessible after booking', function () { $this->withSession(['success' => 'Test success message']) ->get(route('booking.success')) ->assertOk() ->assertSee(__('booking.success_title')); }); test('form validation requires all fields', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); Volt::test('pages.booking') ->call('selectSlot', now()->addDay()->format('Y-m-d'), '09:00') ->set('guestName', '') ->set('guestEmail', '') ->set('guestPhone', '') ->set('problemSummary', '') ->set('captchaAnswer', '') ->call('showConfirm') ->assertHasErrors(['guestName', 'guestEmail', 'guestPhone', 'problemSummary', 'captchaAnswer']); }); test('guest name must be at least 3 characters', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); Volt::test('pages.booking') ->call('selectSlot', now()->addDay()->format('Y-m-d'), '09:00') ->set('guestName', 'AB') ->set('guestEmail', 'test@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'This is a valid problem summary for testing.') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->assertHasErrors(['guestName']); }); test('problem summary must be at least 20 characters', function () { WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '17:00', ]); Volt::test('pages.booking') ->call('selectSlot', now()->addDay()->format('Y-m-d'), '09:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'test@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'Too short') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->assertHasErrors(['problemSummary']); }); test('slot no longer available error is shown', function () { // Create a working hour but no available slots WorkingHour::factory()->create([ 'day_of_week' => now()->addDay()->dayOfWeek, 'is_active' => true, 'start_time' => '09:00', 'end_time' => '10:00', ]); $date = now()->addDay()->format('Y-m-d'); // Book the only available slot Consultation::factory()->guest()->create([ 'booking_date' => $date, 'booking_time' => '09:00', 'status' => ConsultationStatus::Approved, ]); // Try to book the same slot Volt::test('pages.booking') ->call('selectSlot', $date, '09:00') ->set('guestName', 'John Doe') ->set('guestEmail', 'different@example.com') ->set('guestPhone', '+970599123456') ->set('problemSummary', 'I need legal advice regarding a contract dispute.') ->set('captchaAnswer', session('captcha_answer')) ->call('showConfirm') ->assertHasErrors(['selectedTime']); });