singleloginsystem/tests/Feature/TicketSearchAndPaginationTest.php
= 8a41ae6ac1 Feat: assigned user status change, search, pagination and notification
- Added activity logs for ticket status changes, comments, and ticket views.
- Implemented `TicketStatusChangedNotification` to notify users of status updates.
- Enhanced ticket list filtering with pagination, search, and status filters.
- Updated UI to better handle ticket assignments, status updates, and comment notifications.
- Extended tests for activity logs, unauthorized actions, status change notifications, and filtering functionalities.
2026-05-28 13:22:36 +00:00

189 lines
5.9 KiB
PHP

<?php
declare(strict_types=1);
use App\Data\Ticket\CreateTicketRequest;
use App\Enums\TicketStatusEnum;
use App\Models\{Ticket, User};
use App\Services\TicketService;
use Database\Seeders\DatabaseSeeder;
use Livewire\Livewire;
beforeEach(function (): void {
$this->seed(DatabaseSeeder::class);
});
test('anyone can search tickets by ticket id', function (): void {
$user = User::factory()->create();
$user->assignRole('user');
$this->actingAs($user);
$service = app(TicketService::class);
// Create Ticket 1
$dto1 = new CreateTicketRequest(
userId: $user->id,
connectedAppId: null,
issueCategory: 'Technical Issue',
description: 'First test ticket.',
notifiedRoleIds: [],
notifiedUserIds: [],
attachment: null,
);
$ticket1Data = $service->create($dto1);
// Create Ticket 2
$dto2 = new CreateTicketRequest(
userId: $user->id,
connectedAppId: null,
issueCategory: 'Billing Query',
description: 'Second test ticket.',
notifiedRoleIds: [],
notifiedUserIds: [],
attachment: null,
);
$ticket2Data = $service->create($dto2);
// Search by Ticket 1 code/ID using Livewire component
Livewire::test('pages::tickets.index')
->set('search', $ticket1Data->ticketId)
->assertSee($ticket1Data->ticketId)
->assertDontSee($ticket2Data->ticketId);
// Search by Ticket 2 code/ID
Livewire::test('pages::tickets.index')
->set('search', $ticket2Data->ticketId)
->assertSee($ticket2Data->ticketId)
->assertDontSee($ticket1Data->ticketId);
});
test('tickets table is paginated to 10 items per page', function (): void {
$user = User::factory()->create();
$user->assignRole('user');
$this->actingAs($user);
$service = app(TicketService::class);
// Create 12 tickets
$createdTicketIds = [];
for ($i = 1; $i <= 12; $i++) {
$dto = new CreateTicketRequest(
userId: $user->id,
connectedAppId: null,
issueCategory: 'Technical Issue',
description: "Ticket number {$i}.",
notifiedRoleIds: [],
notifiedUserIds: [],
attachment: null,
);
$ticketData = $service->create($dto);
Ticket::where('id', $ticketData->id)->update([
'created_at' => now()->addSeconds($i),
]);
$createdTicketIds[] = $ticketData->ticketId;
}
$component = Livewire::test('pages::tickets.index');
// On page 1, we should see the latest 10 tickets (since we order by latest, the last 10 created)
$page1Tickets = array_slice(array_reverse($createdTicketIds), 0, 10);
$page2Tickets = array_slice(array_reverse($createdTicketIds), 10, 2);
foreach ($page1Tickets as $id) {
$component->assertSee($id);
}
foreach ($page2Tickets as $id) {
$component->assertDontSee($id);
}
// Go to page 2
$component->call('gotoPage', 2);
foreach ($page1Tickets as $id) {
$component->assertDontSee($id);
}
foreach ($page2Tickets as $id) {
$component->assertSee($id);
}
});
test('status filtering works on paginated data at query level', function (): void {
$user = User::factory()->create();
$user->assignRole('user');
$this->actingAs($user);
$service = app(TicketService::class);
$admin = User::where('email', 'admin@example.com')->firstOrFail();
// Create Ticket 1 (Open status by default)
$dto1 = new CreateTicketRequest(
userId: $user->id,
connectedAppId: null,
issueCategory: 'Technical Issue',
description: 'Open ticket.',
notifiedRoleIds: [],
notifiedUserIds: [],
attachment: null,
);
$ticket1Data = $service->create($dto1);
// Create Ticket 2 and change its status to Hold
$dto2 = new CreateTicketRequest(
userId: $user->id,
connectedAppId: null,
issueCategory: 'Billing Query',
description: 'Hold ticket.',
notifiedRoleIds: [],
notifiedUserIds: [],
attachment: null,
);
$ticket2Data = $service->create($dto2);
// Act as admin to change status
$this->actingAs($admin);
$service->updateStatus($ticket2Data->id, TicketStatusEnum::Hold->value);
// Act as user to view
$this->actingAs($user);
// Filter by Open
Livewire::test('pages::tickets.index')
->set('statusFilter', TicketStatusEnum::Open->value)
->assertSee($ticket1Data->ticketId)
->assertDontSee($ticket2Data->ticketId);
// Filter by Hold
Livewire::test('pages::tickets.index')
->set('statusFilter', TicketStatusEnum::Hold->value)
->assertSee($ticket2Data->ticketId)
->assertDontSee($ticket1Data->ticketId);
});
test('normal user can see status filter and see custom empty state message when no results match search', function (): void {
$user = User::factory()->create();
$user->assignRole('user');
$this->actingAs($user);
// Initial load: Should see default empty state message
Livewire::test('pages::tickets.index')
->assertSee('No Support Tickets Found')
->assertDontSee('No Matching Tickets Found')
->assertSee('You have not raised any support tickets yet.');
// Search for non-existent ticket ID: Should see the custom empty search state message
Livewire::test('pages::tickets.index')
->set('search', 'TKT-NONEXISTENT-99')
->assertSee('No Matching Tickets Found')
->assertDontSee('No Support Tickets Found')
->assertSee('matching your search query or filter criteria');
// Filter by Hold status: Should see the custom empty filter state message
Livewire::test('pages::tickets.index')
->set('statusFilter', 'hold')
->assertSee('No Matching Tickets Found')
->assertDontSee('No Support Tickets Found')
->assertSee('matching your search query or filter criteria');
});