- Added database migrations for tickets, statuses, roles, users, and related associations. - Introduced models and enums for ticket status, permissions, and notifications. - Implemented `TicketService` for ticket management and notification handling. - Created Livewire form and UI for raising tickets with file attachments and routing options. - Added tests covering ticket creation, validation, notifications, and file uploads.
186 lines
5.7 KiB
PHP
186 lines
5.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Data\Ticket\CreateTicketRequest;
|
|
use App\Enums\TicketStatusEnum;
|
|
use App\Models\{ConnectedApp, Role, User};
|
|
use App\Notifications\TicketRaisedNotification;
|
|
use App\Services\TicketService;
|
|
use Database\Seeders\DatabaseSeeder;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\{Notification, Storage};
|
|
use Livewire\Livewire;
|
|
|
|
beforeEach(function (): void {
|
|
$this->seed(DatabaseSeeder::class);
|
|
});
|
|
|
|
test('guests cannot access the tickets page', function (): void {
|
|
$this->get(route('tickets.index'))
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('authenticated users with correct permissions can access the tickets page', function (): void {
|
|
$user = User::factory()->create();
|
|
$user->assignRole('user');
|
|
$this->actingAs($user);
|
|
|
|
$this->get(route('tickets.index'))
|
|
->assertOk()
|
|
->assertSee('Support Tickets');
|
|
});
|
|
|
|
test('submitting a support ticket creates the ticket and generates a unique ticket ID', function (): void {
|
|
$user = User::factory()->create();
|
|
$user->assignRole('user');
|
|
$this->actingAs($user);
|
|
|
|
$app = ConnectedApp::first();
|
|
$supportRole = Role::where('name', 'Support')->firstOrFail();
|
|
|
|
$dto = new CreateTicketRequest(
|
|
userId: $user->id,
|
|
connectedAppId: $app->id,
|
|
issueCategory: 'Billing Query',
|
|
description: 'Need assistance with billing renewal.',
|
|
notifiedRoleIds: [$supportRole->id],
|
|
notifiedUserIds: [],
|
|
attachment: null,
|
|
);
|
|
|
|
$service = app(TicketService::class);
|
|
$ticketData = $service->create($dto);
|
|
|
|
expect($ticketData->ticketId)->toStartWith('TKT-')
|
|
->and(mb_strlen($ticketData->ticketId))->toBe(12)
|
|
->and($ticketData->issueCategory)->toBe('Billing Query')
|
|
->and($ticketData->statusSlug)->toBe(TicketStatusEnum::Open->value)
|
|
->and($ticketData->notifiedRoleNames)->toContain('Support');
|
|
|
|
$this->assertDatabaseHas('tickets', [
|
|
'user_id' => $user->id,
|
|
'connected_app_id' => $app->id,
|
|
'issue_category' => 'Billing Query',
|
|
]);
|
|
|
|
$this->assertDatabaseHas('ticket_notified_roles', [
|
|
'ticket_id' => $ticketData->id,
|
|
'role_id' => $supportRole->id,
|
|
]);
|
|
});
|
|
|
|
test('submitting a ticket with category Others requires at least 20 characters for description', function (): void {
|
|
$user = User::factory()->create();
|
|
$user->assignRole('user');
|
|
$this->actingAs($user);
|
|
|
|
$supportRole = Role::where('name', 'Support')->firstOrFail();
|
|
|
|
// Test Validation Failure via Livewire component form object
|
|
Livewire::test('pages::tickets.index')
|
|
->set('form.issueCategory', 'Others')
|
|
->set('form.description', 'Short desc')
|
|
->set('form.routingType', 'role')
|
|
->set('form.notifiedRoleIds', [$supportRole->id])
|
|
->call('saveTicket')
|
|
->assertHasErrors(['form.description' => 'min']);
|
|
});
|
|
|
|
test('attaching a file for Others category uploads and stores the file', function (): void {
|
|
Storage::fake('public');
|
|
|
|
$user = User::factory()->create();
|
|
$user->assignRole('user');
|
|
$this->actingAs($user);
|
|
|
|
$supportRole = Role::where('name', 'Support')->firstOrFail();
|
|
$file = UploadedFile::fake()->create('screenshot.png', 500);
|
|
|
|
$dto = new CreateTicketRequest(
|
|
userId: $user->id,
|
|
connectedAppId: null,
|
|
issueCategory: 'Others',
|
|
description: 'A very detailed query containing more than twenty characters.',
|
|
notifiedRoleIds: [$supportRole->id],
|
|
notifiedUserIds: [],
|
|
attachment: $file,
|
|
);
|
|
|
|
$service = app(TicketService::class);
|
|
$ticketData = $service->create($dto);
|
|
|
|
$this->assertDatabaseHas('ticket_attachments', [
|
|
'file_name' => 'screenshot.png',
|
|
'mime_type' => 'image/png',
|
|
]);
|
|
|
|
expect(count($ticketData->attachments))->toBe(1);
|
|
Storage::disk('public')->assertExists($ticketData->attachments[0]['file_path']);
|
|
});
|
|
|
|
test('notification routing to a specific user triggers notification to that user', function (): void {
|
|
Notification::fake();
|
|
|
|
$user = User::factory()->create();
|
|
$user->assignRole('user');
|
|
$this->actingAs($user);
|
|
|
|
$adminUser = User::where('email', 'admin@example.com')->firstOrFail();
|
|
|
|
$dto = new CreateTicketRequest(
|
|
userId: $user->id,
|
|
connectedAppId: null,
|
|
issueCategory: 'Technical Issue',
|
|
description: 'SSO log-in error.',
|
|
notifiedRoleIds: [],
|
|
notifiedUserIds: [$adminUser->id],
|
|
attachment: null,
|
|
);
|
|
|
|
$service = app(TicketService::class);
|
|
$service->create($dto);
|
|
|
|
Notification::assertSentTo(
|
|
$adminUser,
|
|
TicketRaisedNotification::class
|
|
);
|
|
});
|
|
|
|
test('notification routing to multiple roles triggers notifications to all users assigned to those roles', function (): void {
|
|
Notification::fake();
|
|
|
|
$user = User::factory()->create();
|
|
$user->assignRole('user');
|
|
$this->actingAs($user);
|
|
|
|
$supportRole = Role::where('name', 'Support')->firstOrFail();
|
|
$managerRole = Role::where('name', 'Manager')->firstOrFail();
|
|
|
|
// Create a support user
|
|
$supportUser = User::factory()->create();
|
|
$supportUser->assignRole($supportRole);
|
|
|
|
// Create a manager user
|
|
$managerUser = User::factory()->create();
|
|
$managerUser->assignRole($managerRole);
|
|
|
|
$dto = new CreateTicketRequest(
|
|
userId: $user->id,
|
|
connectedAppId: null,
|
|
issueCategory: 'Service Extension',
|
|
description: 'Requesting 3 days trial extension.',
|
|
notifiedRoleIds: [$supportRole->id, $managerRole->id],
|
|
notifiedUserIds: [],
|
|
attachment: null,
|
|
);
|
|
|
|
$service = app(TicketService::class);
|
|
$service->create($dto);
|
|
|
|
Notification::assertSentTo(
|
|
[$supportUser, $managerUser],
|
|
TicketRaisedNotification::class
|
|
);
|
|
});
|