libra/tests/Feature/Client/ConsultationsViewTest.php

390 lines
12 KiB
PHP

<?php
use App\Enums\ConsultationStatus;
use App\Enums\ConsultationType;
use App\Enums\PaymentStatus;
use App\Models\Consultation;
use App\Models\User;
use Livewire\Volt\Volt;
// Access Control Tests
test('unauthenticated user is redirected to login', function () {
$this->get(route('client.consultations.index'))
->assertRedirect(route('login'));
});
test('client can view their consultations page', function () {
$user = User::factory()->individual()->create();
$this->actingAs($user)
->get(route('client.consultations.index'))
->assertOk();
});
test('admin cannot access client consultations page', function () {
$admin = User::factory()->admin()->create();
$this->actingAs($admin)
->get(route('client.consultations.index'))
->assertForbidden();
});
test('user sees only their own consultations', function () {
$user = User::factory()->individual()->create();
$otherUser = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(3),
'booking_time' => '09:00:00',
]);
Consultation::factory()->approved()->create([
'user_id' => $otherUser->id,
'booking_date' => today()->addDays(2),
'booking_time' => '14:00:00',
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee('9:00 AM')
->assertDontSee('2:00 PM');
});
// Upcoming Section Tests
test('upcoming section shows approved consultations with future date', function () {
$user = User::factory()->individual()->create();
$consultation = Consultation::factory()->approved()->free()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(3),
'booking_time' => '10:00:00',
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee('10:00 AM')
->assertSee(__('booking.type_free'));
});
test('upcoming section is sorted by date ascending', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(5),
'booking_time' => '11:00:00',
]);
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(2),
'booking_time' => '09:00:00',
]);
$this->actingAs($user);
$component = Volt::test('client.consultations.index');
// The earlier date should appear first in upcoming
$html = $component->html();
$pos1 = strpos($html, '9:00 AM');
$pos2 = strpos($html, '11:00 AM');
expect($pos1)->toBeLessThan($pos2);
});
test('upcoming section displays consultation type correctly', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->free()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(2),
]);
Consultation::factory()->approved()->paid()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(3),
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.type_free'))
->assertSee(__('booking.type_paid'));
});
test('upcoming section shows payment status for paid consultations', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(2),
'consultation_type' => ConsultationType::Paid,
'payment_status' => PaymentStatus::Pending,
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.payment_pending'));
});
test('upcoming section shows payment received badge when payment is received', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(2),
'consultation_type' => ConsultationType::Paid,
'payment_status' => PaymentStatus::Received,
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.payment_received'));
});
test('calendar download button is available for upcoming approved consultations', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(2),
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.add_to_calendar'));
});
// Pending Section Tests
test('pending section shows consultations with pending status', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->pending()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(5),
'problem_summary' => 'This is my pending consultation request',
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee('This is my pending consultation')
->assertSee(__('booking.pending_review'));
});
test('pending section shows submission date', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->pending()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(5),
'created_at' => now(),
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.submitted_on'));
});
test('pending section truncates long problem summary', function () {
$user = User::factory()->individual()->create();
$longSummary = str_repeat('This is a very long problem summary. ', 20);
Consultation::factory()->pending()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(5),
'problem_summary' => $longSummary,
]);
$this->actingAs($user);
// The summary should be truncated (not show full text)
Volt::test('client.consultations.index')
->assertDontSee($longSummary);
});
// Past Section Tests
test('past section shows completed consultations', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->completed()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays(5),
'booking_time' => '14:00:00',
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee('2:00 PM');
});
test('past section shows cancelled consultations', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->cancelled()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays(3),
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(ConsultationStatus::Cancelled->label());
});
test('past section shows no-show consultations', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->noShow()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays(3),
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(ConsultationStatus::NoShow->label());
});
test('past section shows approved consultations with past date', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays(2),
'booking_time' => '16:00:00',
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee('4:00 PM');
});
test('past section is sorted by date descending', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->completed()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays(10),
'booking_time' => '09:00:00',
]);
Consultation::factory()->completed()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays(2),
'booking_time' => '15:00:00',
]);
$this->actingAs($user);
$component = Volt::test('client.consultations.index');
$html = $component->html();
// The more recent date should appear first in past section
$pos1 = strpos($html, '3:00 PM');
$pos2 = strpos($html, '9:00 AM');
expect($pos1)->toBeLessThan($pos2);
});
test('past section paginates correctly', function () {
$user = User::factory()->individual()->create();
// Create 15 completed consultations with unique times for identification
for ($i = 1; $i <= 15; $i++) {
Consultation::factory()->completed()->create([
'user_id' => $user->id,
'booking_date' => today()->subDays($i),
'booking_time' => sprintf('%02d:00:00', $i),
]);
}
$this->actingAs($user);
// First page should show 10 items, ordered by booking_date desc
// So items with booking_date subDays(1) through subDays(10) should appear
// Items with subDays(11) through subDays(15) should NOT appear on first page
$component = Volt::test('client.consultations.index');
// The 11th, 12th, 13th, 14th, 15th items (oldest) should NOT be on the first page
// booking_time 11:00, 12:00, 13:00, 14:00, 15:00 correspond to the oldest items
$component->assertDontSee('11:00 AM')
->assertDontSee('12:00 PM')
->assertDontSee('1:00 PM')
->assertDontSee('2:00 PM')
->assertDontSee('3:00 PM');
});
// Empty States Tests
test('empty upcoming shows appropriate message with link to book', function () {
$user = User::factory()->individual()->create();
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.no_upcoming_consultations'))
->assertSee(__('booking.book_consultation'));
});
test('empty pending shows appropriate message', function () {
$user = User::factory()->individual()->create();
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.no_pending_requests'));
});
test('empty past shows appropriate message', function () {
$user = User::factory()->individual()->create();
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.no_past_consultations'));
});
// Read-only Tests
test('consultations page is read only with no edit capabilities', function () {
$user = User::factory()->individual()->create();
Consultation::factory()->approved()->create([
'user_id' => $user->id,
'booking_date' => today()->addDays(3),
]);
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertDontSee('Edit')
->assertDontSee('Cancel')
->assertDontSee('Delete');
});
// Section Heading Tests
test('page displays all section headings', function () {
$user = User::factory()->individual()->create();
$this->actingAs($user);
Volt::test('client.consultations.index')
->assertSee(__('booking.my_consultations'))
->assertSee(__('booking.upcoming_consultations'))
->assertSee(__('booking.pending_requests'))
->assertSee(__('booking.past_consultations'));
});
// Company Client Tests
test('company client can view consultations page', function () {
$user = User::factory()->company()->create();
$this->actingAs($user)
->get(route('client.consultations.index'))
->assertOk();
});