pases 5 ticket updates
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\tests\Feature;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class TicketCreateEditorSyncFilesTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function ticket_create_editor_pushes_details_body_to_livewire_before_validation(): void
|
||||
{
|
||||
$view = file_get_contents(base_path('Modules/Helpdesk/Resources/views/livewire/ticket-create.blade.php'));
|
||||
|
||||
$this->assertIsString($view);
|
||||
$this->assertStringContainsString('wire:model.live="body"', $view);
|
||||
$this->assertStringContainsString("window.Livewire.find(livewireId).set('body', value, false)", $view);
|
||||
$this->assertStringContainsString("form.addEventListener('submit', syncBody, { capture: true })", $view);
|
||||
$this->assertStringContainsString("document.addEventListener('livewire:navigated', initialiseTicketCreateEditor)", $view);
|
||||
$this->assertStringContainsString("editor.addEventListener('paste', () => window.setTimeout(syncBody, 0))", $view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Tests\Feature;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class TicketFirstResponseSlaFilesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Public replies must satisfy the first-response SLA instead of only incrementing the counter.
|
||||
*/
|
||||
public function test_public_response_updates_first_response_sla_state(): void
|
||||
{
|
||||
$servicePath = dirname(__DIR__, 2).'/Services/SlaService.php';
|
||||
|
||||
self::assertFileExists($servicePath);
|
||||
|
||||
$service = file_get_contents($servicePath);
|
||||
|
||||
self::assertIsString($service);
|
||||
self::assertStringContainsString('public function recordPublicResponse(Ticket $ticket, User $actor): void', $service);
|
||||
self::assertStringContainsString('markFirstResponse($ticket, $respondedAt, $actor)', $service);
|
||||
self::assertStringNotContainsString('(int) $ticket->user_id !== (int) $actor->id', $service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Existing tickets with public comments but a missing first_response_at are repaired on display.
|
||||
*/
|
||||
public function test_ticket_show_synchronises_first_response_from_existing_public_comments(): void
|
||||
{
|
||||
$componentPath = dirname(__DIR__, 2).'/Livewire/TicketShow.php';
|
||||
$servicePath = dirname(__DIR__, 2).'/Services/SlaService.php';
|
||||
|
||||
$component = file_get_contents($componentPath);
|
||||
$service = file_get_contents($servicePath);
|
||||
|
||||
self::assertIsString($component);
|
||||
self::assertIsString($service);
|
||||
self::assertStringContainsString('syncFirstResponseFromComments($ticket)', $component);
|
||||
self::assertStringContainsString("where('is_internal', false)", $service);
|
||||
self::assertStringContainsString("whereNull('tombstoned_at')", $service);
|
||||
}
|
||||
|
||||
/**
|
||||
* The SLA card should show an accurate response state instead of Awaiting response after public replies exist.
|
||||
*/
|
||||
public function test_sla_card_has_clear_responded_and_awaiting_public_reply_states(): void
|
||||
{
|
||||
$viewPath = dirname(__DIR__, 2).'/Resources/views/livewire/ticket-show.blade.php';
|
||||
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('Responded', $view);
|
||||
self::assertStringContainsString('Awaiting public reply', $view);
|
||||
self::assertStringNotContainsString("?? 'Awaiting response'", $view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Tests\Feature;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class TicketPublicResponseVisibilityFilesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Ensure the main ticket response form has an explicit public/internal visibility choice.
|
||||
*/
|
||||
public function test_main_ticket_response_form_has_public_visibility_control(): void
|
||||
{
|
||||
$viewPath = dirname(__DIR__, 2).'/Resources/views/livewire/ticket-show.blade.php';
|
||||
|
||||
self::assertFileExists($viewPath);
|
||||
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('Visibility', $view);
|
||||
self::assertStringContainsString('Public reply', $view);
|
||||
self::assertStringContainsString('Internal note', $view);
|
||||
self::assertStringContainsString('name="internal" value="0"', $view);
|
||||
self::assertStringContainsString('name="internal" value="1"', $view);
|
||||
self::assertStringContainsString('counts as the first SLA response', $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure threaded responses have the same public/internal visibility choice and visible badges.
|
||||
*/
|
||||
public function test_threaded_responses_have_public_visibility_control_and_badges(): void
|
||||
{
|
||||
$partialPath = dirname(__DIR__, 2).'/Resources/views/partials/comment-thread.blade.php';
|
||||
|
||||
self::assertFileExists($partialPath);
|
||||
|
||||
$partial = file_get_contents($partialPath);
|
||||
|
||||
self::assertIsString($partial);
|
||||
self::assertStringContainsString('Public reply', $partial);
|
||||
self::assertStringContainsString('Internal note', $partial);
|
||||
self::assertStringContainsString('name="internal" value="0" checked', $partial);
|
||||
self::assertStringContainsString('name="internal" value="1"', $partial);
|
||||
self::assertStringContainsString('>Public</span>', $partial);
|
||||
self::assertStringContainsString('>Internal</span>', $partial);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Tests\Feature;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class TicketSlaOperationalDetailFilesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* SLA cards must show operationally useful first-response detail.
|
||||
*/
|
||||
public function test_first_response_sla_card_shows_duration_responder_and_timestamp(): void
|
||||
{
|
||||
$componentPath = dirname(__DIR__, 2).'/Livewire/TicketShow.php';
|
||||
$viewPath = dirname(__DIR__, 2).'/Resources/views/livewire/ticket-show.blade.php';
|
||||
|
||||
$component = file_get_contents($componentPath);
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($component);
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('firstResponseSlaDetail', $component);
|
||||
self::assertStringContainsString('Responded in ', $component);
|
||||
self::assertStringContainsString('firstResponderName', $component);
|
||||
self::assertStringContainsString('Responder', $view);
|
||||
self::assertStringContainsString('Responded at', $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* SLA cards should use clear met, due-soon and breached states.
|
||||
*/
|
||||
public function test_sla_cards_have_colour_coded_state_helpers(): void
|
||||
{
|
||||
$componentPath = dirname(__DIR__, 2).'/Livewire/TicketShow.php';
|
||||
$viewPath = dirname(__DIR__, 2).'/Resources/views/livewire/ticket-show.blade.php';
|
||||
|
||||
$component = file_get_contents($componentPath);
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($component);
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('firstResponseIsDueSoon', $component);
|
||||
self::assertStringContainsString('resolutionIsDueSoon', $component);
|
||||
self::assertStringContainsString('firstResponseSlaClasses', $view);
|
||||
self::assertStringContainsString('resolutionSlaClasses', $view);
|
||||
self::assertStringContainsString('border-amber-300', $component);
|
||||
self::assertStringContainsString('border-red-300', $component);
|
||||
self::assertStringContainsString('border-emerald-200', $component);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ticket page should expose an SLA audit trail for support managers.
|
||||
*/
|
||||
public function test_sla_audit_trail_is_visible_on_ticket_page(): void
|
||||
{
|
||||
$servicePath = dirname(__DIR__, 2).'/Services/SlaService.php';
|
||||
$viewPath = dirname(__DIR__, 2).'/Resources/views/livewire/ticket-show.blade.php';
|
||||
|
||||
$service = file_get_contents($servicePath);
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($service);
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('SLA audit trail', $view);
|
||||
self::assertStringContainsString('$ticket->slaEvents->take(5)', $view);
|
||||
self::assertStringContainsString('actor_name', $service);
|
||||
self::assertStringContainsString('response_seconds', $service);
|
||||
self::assertStringContainsString('resolved_seconds', $service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public reply counts must include threaded public replies, not only root comments.
|
||||
*/
|
||||
public function test_public_reply_count_uses_all_ticket_comments(): void
|
||||
{
|
||||
$componentPath = dirname(__DIR__, 2).'/Livewire/TicketShow.php';
|
||||
|
||||
$component = file_get_contents($componentPath);
|
||||
|
||||
self::assertIsString($component);
|
||||
self::assertStringContainsString('Comment::query()', $component);
|
||||
self::assertStringContainsString("where('ticket_id', \$ticket->id)", $component);
|
||||
self::assertStringContainsString("\$comments->where('is_internal', false)->count()", $component);
|
||||
self::assertStringNotContainsString('$ticket->comments()
|
||||
->active()', $component);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Tests\Feature;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class TicketTimerButtonSizeFilesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Ensure the inactive timer action remains readable, single-line, and does not reintroduce unused script files.
|
||||
*/
|
||||
public function test_start_timer_button_uses_readable_single_line_professional_classes(): void
|
||||
{
|
||||
$viewPath = dirname(__DIR__, 2) . '/Resources/views/livewire/ticket-timer.blade.php';
|
||||
|
||||
self::assertFileExists($viewPath);
|
||||
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('data-dusk="start-ticket-timer"', $view);
|
||||
self::assertStringContainsString('min-w-[9.5rem]', $view);
|
||||
self::assertStringContainsString('whitespace-nowrap rounded-md bg-blue-600 px-4 py-2 text-sm', $view);
|
||||
self::assertStringNotContainsString('px-3 py-1.5 text-xs', $view);
|
||||
self::assertStringNotContainsString('ticket-timer.js', $view);
|
||||
}
|
||||
/**
|
||||
* Ensure the active timer action also remains readable and single-line.
|
||||
*/
|
||||
public function test_end_timer_button_uses_matching_readable_single_line_professional_classes(): void
|
||||
{
|
||||
$viewPath = dirname(__DIR__, 2) . '/Resources/views/livewire/ticket-timer.blade.php';
|
||||
|
||||
self::assertFileExists($viewPath);
|
||||
|
||||
$view = file_get_contents($viewPath);
|
||||
|
||||
self::assertIsString($view);
|
||||
self::assertStringContainsString('data-dusk="end-ticket-timer"', $view);
|
||||
self::assertStringContainsString('min-w-[9.5rem] shrink-0 items-center justify-center whitespace-nowrap rounded-md bg-red-600 px-4 py-2 text-sm', $view);
|
||||
self::assertStringNotContainsString('rounded-lg bg-red-600 px-4 py-2.5 text-sm', $view);
|
||||
self::assertStringNotContainsString('ticket-timer.js', $view);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,19 @@ final class TicketReferenceServiceTest extends TestCase
|
||||
|
||||
self::assertSame('HD-'.now()->format('Y').'-00042', $reference);
|
||||
}
|
||||
|
||||
public function test_it_does_not_reuse_soft_deleted_ticket_references(): void
|
||||
{
|
||||
$year = now()->format('Y');
|
||||
$ticket = $this->ticket(['reference' => 'HD-'.$year.'-00002']);
|
||||
|
||||
$ticket->delete();
|
||||
|
||||
$reference = app(TicketReferenceService::class)->next();
|
||||
|
||||
self::assertSame('HD-'.$year.'-00003', $reference);
|
||||
}
|
||||
|
||||
public function test_it_uses_the_highest_reference_suffix_instead_of_latest_database_id(): void
|
||||
{
|
||||
$year = now()->format('Y');
|
||||
|
||||
Reference in New Issue
Block a user