test: add Livewire component tests for all 12 admin components
Closes #11 Adds comprehensive Livewire tests in tests/Feature/Livewire/ covering: - DashboardTest: stats structure, refresh action, blocked alert, quick links - PlansTest: auth, filters, activate/complete/archive/delete actions - PlanDetailTest: auth, plan loading, phase actions, task validation - SessionsTest: auth, filters, pause/resume/complete/fail actions - SessionDetailTest: auth, polling, modal states, session control - ToolAnalyticsTest: auth, setDays, filters, success rate colour helpers - ApiKeysTest: auth, create/edit/revoke modals, validation, stats - ApiKeyManagerTest: workspace binding, create form, toggleScope - ToolCallsTest: auth, filters, viewCall/closeCallDetail, badge helpers - RequestLogTest: filters, selectRequest/closeDetail interactions - TemplatesTest: auth, preview/import/create modals, clearFilters - PlaygroundTest: server loading, API key validation, execute behaviour Infrastructure: - LivewireTestCase base class with stub view namespace registration - HadesUser fixture for auth()->user()->isHades() checks - Minimal stub blade views in tests/views/ (agentic and mcp namespaces) - composer.json: add livewire/livewire and pest-plugin-livewire to require-dev; fix autoload-dev paths to lowercase tests/ directory Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
10b6260c4c
commit
2ba1751081
28 changed files with 2034 additions and 2 deletions
|
|
@ -14,8 +14,10 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.18",
|
||||
"livewire/livewire": "^3.0",
|
||||
"orchestra/testbench": "^9.0|^10.0",
|
||||
"pestphp/pest": "^3.0"
|
||||
"pestphp/pest": "^3.0",
|
||||
"pestphp/pest-plugin-livewire": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
@ -25,7 +27,8 @@
|
|||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Core\\Mod\\Agentic\\Tests\\": "Tests/"
|
||||
"Core\\Mod\\Agentic\\Tests\\": "tests/",
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
|
|
|
|||
140
tests/Feature/Livewire/ApiKeyManagerTest.php
Normal file
140
tests/Feature/Livewire/ApiKeyManagerTest.php
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\ApiKeyManager;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Livewire\Livewire;
|
||||
|
||||
/**
|
||||
* Tests for the ApiKeyManager Livewire component.
|
||||
*
|
||||
* Note: This component manages workspace API keys via Core\Api\Models\ApiKey
|
||||
* (from host-uk/core). Tests for key creation require the full core package
|
||||
* to be installed. Tests here focus on component state and validation.
|
||||
*/
|
||||
class ApiKeyManagerTest extends LivewireTestCase
|
||||
{
|
||||
private Workspace $workspace;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_workspace(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_mount_loads_workspace(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace]);
|
||||
|
||||
$this->assertEquals($this->workspace->id, $component->instance()->workspace->id);
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->assertSet('showCreateModal', false)
|
||||
->assertSet('newKeyName', '')
|
||||
->assertSet('newKeyExpiry', 'never')
|
||||
->assertSet('showNewKeyModal', false)
|
||||
->assertSet('newPlainKey', null);
|
||||
}
|
||||
|
||||
public function test_open_create_modal_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->call('openCreateModal')
|
||||
->assertSet('showCreateModal', true);
|
||||
}
|
||||
|
||||
public function test_open_create_modal_resets_form(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->set('newKeyName', 'Old Name')
|
||||
->call('openCreateModal')
|
||||
->assertSet('newKeyName', '')
|
||||
->assertSet('newKeyExpiry', 'never');
|
||||
}
|
||||
|
||||
public function test_close_create_modal_hides_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->call('openCreateModal')
|
||||
->call('closeCreateModal')
|
||||
->assertSet('showCreateModal', false);
|
||||
}
|
||||
|
||||
public function test_create_key_requires_name(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->call('openCreateModal')
|
||||
->set('newKeyName', '')
|
||||
->call('createKey')
|
||||
->assertHasErrors(['newKeyName' => 'required']);
|
||||
}
|
||||
|
||||
public function test_create_key_validates_name_max_length(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->call('openCreateModal')
|
||||
->set('newKeyName', str_repeat('x', 101))
|
||||
->call('createKey')
|
||||
->assertHasErrors(['newKeyName' => 'max']);
|
||||
}
|
||||
|
||||
public function test_toggle_scope_adds_scope_if_not_present(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->set('newKeyScopes', [])
|
||||
->call('toggleScope', 'read')
|
||||
->assertSet('newKeyScopes', ['read']);
|
||||
}
|
||||
|
||||
public function test_toggle_scope_removes_scope_if_already_present(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->set('newKeyScopes', ['read', 'write'])
|
||||
->call('toggleScope', 'read')
|
||||
->assertSet('newKeyScopes', ['write']);
|
||||
}
|
||||
|
||||
public function test_close_new_key_modal_clears_plain_key(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeyManager::class, ['workspace' => $this->workspace])
|
||||
->set('newPlainKey', 'secret-key-value')
|
||||
->set('showNewKeyModal', true)
|
||||
->call('closeNewKeyModal')
|
||||
->assertSet('newPlainKey', null)
|
||||
->assertSet('showNewKeyModal', false);
|
||||
}
|
||||
}
|
||||
238
tests/Feature/Livewire/ApiKeysTest.php
Normal file
238
tests/Feature/Livewire/ApiKeysTest.php
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\Models\AgentApiKey;
|
||||
use Core\Mod\Agentic\View\Modal\Admin\ApiKeys;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class ApiKeysTest extends LivewireTestCase
|
||||
{
|
||||
private Workspace $workspace;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
}
|
||||
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(ApiKeys::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('perPage', 25)
|
||||
->assertSet('showCreateModal', false)
|
||||
->assertSet('showEditModal', false);
|
||||
}
|
||||
|
||||
public function test_open_create_modal_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openCreateModal')
|
||||
->assertSet('showCreateModal', true);
|
||||
}
|
||||
|
||||
public function test_close_create_modal_hides_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openCreateModal')
|
||||
->call('closeCreateModal')
|
||||
->assertSet('showCreateModal', false);
|
||||
}
|
||||
|
||||
public function test_open_create_modal_resets_form_fields(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->set('newKeyName', 'Old Name')
|
||||
->call('openCreateModal')
|
||||
->assertSet('newKeyName', '')
|
||||
->assertSet('newKeyPermissions', [])
|
||||
->assertSet('newKeyRateLimit', 100);
|
||||
}
|
||||
|
||||
public function test_create_key_requires_name(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openCreateModal')
|
||||
->set('newKeyName', '')
|
||||
->set('newKeyWorkspace', $this->workspace->id)
|
||||
->set('newKeyPermissions', [AgentApiKey::PERM_PLANS_READ])
|
||||
->call('createKey')
|
||||
->assertHasErrors(['newKeyName' => 'required']);
|
||||
}
|
||||
|
||||
public function test_create_key_requires_at_least_one_permission(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openCreateModal')
|
||||
->set('newKeyName', 'Test Key')
|
||||
->set('newKeyWorkspace', $this->workspace->id)
|
||||
->set('newKeyPermissions', [])
|
||||
->call('createKey')
|
||||
->assertHasErrors(['newKeyPermissions']);
|
||||
}
|
||||
|
||||
public function test_create_key_requires_valid_workspace(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openCreateModal')
|
||||
->set('newKeyName', 'Test Key')
|
||||
->set('newKeyWorkspace', 99999)
|
||||
->set('newKeyPermissions', [AgentApiKey::PERM_PLANS_READ])
|
||||
->call('createKey')
|
||||
->assertHasErrors(['newKeyWorkspace' => 'exists']);
|
||||
}
|
||||
|
||||
public function test_create_key_validates_rate_limit_minimum(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openCreateModal')
|
||||
->set('newKeyName', 'Test Key')
|
||||
->set('newKeyWorkspace', $this->workspace->id)
|
||||
->set('newKeyPermissions', [AgentApiKey::PERM_PLANS_READ])
|
||||
->set('newKeyRateLimit', 0)
|
||||
->call('createKey')
|
||||
->assertHasErrors(['newKeyRateLimit' => 'min']);
|
||||
}
|
||||
|
||||
public function test_revoke_key_marks_key_as_revoked(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$key = AgentApiKey::generate($this->workspace, 'Test Key', [AgentApiKey::PERM_PLANS_READ]);
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('revokeKey', $key->id)
|
||||
->assertOk();
|
||||
|
||||
$this->assertNotNull($key->fresh()->revoked_at);
|
||||
}
|
||||
|
||||
public function test_clear_filters_resets_workspace_and_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->set('workspace', '1')
|
||||
->set('status', 'active')
|
||||
->call('clearFilters')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('status', '');
|
||||
}
|
||||
|
||||
public function test_open_edit_modal_populates_fields(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$key = AgentApiKey::generate(
|
||||
$this->workspace,
|
||||
'Edit Me',
|
||||
[AgentApiKey::PERM_PLANS_READ],
|
||||
200
|
||||
);
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openEditModal', $key->id)
|
||||
->assertSet('showEditModal', true)
|
||||
->assertSet('editingKeyId', $key->id)
|
||||
->assertSet('editingRateLimit', 200);
|
||||
}
|
||||
|
||||
public function test_close_edit_modal_clears_editing_state(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$key = AgentApiKey::generate($this->workspace, 'Test Key', [AgentApiKey::PERM_PLANS_READ]);
|
||||
|
||||
Livewire::test(ApiKeys::class)
|
||||
->call('openEditModal', $key->id)
|
||||
->call('closeEditModal')
|
||||
->assertSet('showEditModal', false)
|
||||
->assertSet('editingKeyId', null);
|
||||
}
|
||||
|
||||
public function test_get_status_badge_class_returns_green_for_active_key(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$key = AgentApiKey::generate($this->workspace, 'Active Key', [AgentApiKey::PERM_PLANS_READ]);
|
||||
|
||||
$component = Livewire::test(ApiKeys::class);
|
||||
$class = $component->instance()->getStatusBadgeClass($key->fresh());
|
||||
|
||||
$this->assertStringContainsString('green', $class);
|
||||
}
|
||||
|
||||
public function test_get_status_badge_class_returns_red_for_revoked_key(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$key = AgentApiKey::generate($this->workspace, 'Revoked Key', [AgentApiKey::PERM_PLANS_READ]);
|
||||
$key->update(['revoked_at' => now()]);
|
||||
|
||||
$component = Livewire::test(ApiKeys::class);
|
||||
$class = $component->instance()->getStatusBadgeClass($key->fresh());
|
||||
|
||||
$this->assertStringContainsString('red', $class);
|
||||
}
|
||||
|
||||
public function test_stats_returns_array_with_expected_keys(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ApiKeys::class);
|
||||
$stats = $component->instance()->stats;
|
||||
|
||||
$this->assertArrayHasKey('total', $stats);
|
||||
$this->assertArrayHasKey('active', $stats);
|
||||
$this->assertArrayHasKey('revoked', $stats);
|
||||
$this->assertArrayHasKey('total_calls', $stats);
|
||||
}
|
||||
|
||||
public function test_available_permissions_returns_all_permissions(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ApiKeys::class);
|
||||
$permissions = $component->instance()->availablePermissions;
|
||||
|
||||
$this->assertIsArray($permissions);
|
||||
$this->assertNotEmpty($permissions);
|
||||
}
|
||||
}
|
||||
102
tests/Feature/Livewire/DashboardTest.php
Normal file
102
tests/Feature/Livewire/DashboardTest.php
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\Dashboard;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class DashboardTest extends LivewireTestCase
|
||||
{
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(Dashboard::class);
|
||||
}
|
||||
|
||||
public function test_unauthenticated_user_cannot_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(Dashboard::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Dashboard::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_refresh_dispatches_notify_event(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Dashboard::class)
|
||||
->call('refresh')
|
||||
->assertDispatched('notify');
|
||||
}
|
||||
|
||||
public function test_has_correct_initial_properties(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Dashboard::class);
|
||||
|
||||
$component->assertOk();
|
||||
}
|
||||
|
||||
public function test_stats_returns_array_with_expected_keys(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Dashboard::class);
|
||||
|
||||
$stats = $component->instance()->stats;
|
||||
|
||||
$this->assertIsArray($stats);
|
||||
$this->assertArrayHasKey('active_plans', $stats);
|
||||
$this->assertArrayHasKey('total_plans', $stats);
|
||||
$this->assertArrayHasKey('active_sessions', $stats);
|
||||
$this->assertArrayHasKey('today_sessions', $stats);
|
||||
$this->assertArrayHasKey('tool_calls_7d', $stats);
|
||||
$this->assertArrayHasKey('success_rate', $stats);
|
||||
}
|
||||
|
||||
public function test_stat_cards_returns_four_items(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Dashboard::class);
|
||||
|
||||
$cards = $component->instance()->statCards;
|
||||
|
||||
$this->assertIsArray($cards);
|
||||
$this->assertCount(4, $cards);
|
||||
}
|
||||
|
||||
public function test_blocked_alert_is_null_when_no_blocked_plans(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Dashboard::class);
|
||||
|
||||
$this->assertNull($component->instance()->blockedAlert);
|
||||
}
|
||||
|
||||
public function test_quick_links_returns_four_items(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Dashboard::class);
|
||||
|
||||
$links = $component->instance()->quickLinks;
|
||||
|
||||
$this->assertIsArray($links);
|
||||
$this->assertCount(4, $links);
|
||||
}
|
||||
}
|
||||
50
tests/Feature/Livewire/LivewireTestCase.php
Normal file
50
tests/Feature/Livewire/LivewireTestCase.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\Fixtures\HadesUser;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Base test case for Livewire component tests.
|
||||
*
|
||||
* Registers stub view namespaces so components can render during tests
|
||||
* without requiring the full hub/mcp Blade component library.
|
||||
*/
|
||||
abstract class LivewireTestCase extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected HadesUser $hadesUser;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Register stub view namespaces so Livewire can render components
|
||||
// without the full Blade component library from host-uk/core.
|
||||
// Stubs live in tests/views/{namespace}/ and use minimal HTML.
|
||||
$viewsBase = realpath(__DIR__.'/../../views');
|
||||
|
||||
$this->app['view']->addNamespace('agentic', $viewsBase);
|
||||
$this->app['view']->addNamespace('mcp', $viewsBase.'/mcp');
|
||||
|
||||
// Create a Hades-privileged user for component tests
|
||||
$this->hadesUser = new HadesUser([
|
||||
'id' => 1,
|
||||
'name' => 'Hades Test User',
|
||||
'email' => 'hades@test.example',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Act as the Hades user (admin with full access).
|
||||
*/
|
||||
protected function actingAsHades(): static
|
||||
{
|
||||
return $this->actingAs($this->hadesUser);
|
||||
}
|
||||
}
|
||||
229
tests/Feature/Livewire/PlanDetailTest.php
Normal file
229
tests/Feature/Livewire/PlanDetailTest.php
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\Models\AgentPhase;
|
||||
use Core\Mod\Agentic\Models\AgentPlan;
|
||||
use Core\Mod\Agentic\View\Modal\Admin\PlanDetail;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class PlanDetailTest extends LivewireTestCase
|
||||
{
|
||||
private Workspace $workspace;
|
||||
|
||||
private AgentPlan $plan;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
$this->plan = AgentPlan::factory()->draft()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
'slug' => 'test-plan',
|
||||
'title' => 'Test Plan',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug]);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_mount_loads_plan_by_slug(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug]);
|
||||
|
||||
$this->assertEquals($this->plan->id, $component->instance()->plan->id);
|
||||
$this->assertEquals('Test Plan', $component->instance()->plan->title);
|
||||
}
|
||||
|
||||
public function test_has_default_modal_states(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->assertSet('showAddTaskModal', false)
|
||||
->assertSet('selectedPhaseId', 0)
|
||||
->assertSet('newTaskName', '')
|
||||
->assertSet('newTaskNotes', '');
|
||||
}
|
||||
|
||||
public function test_activate_plan_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('activatePlan')
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPlan::STATUS_ACTIVE, $this->plan->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_complete_plan_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$activePlan = AgentPlan::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
'slug' => 'active-plan',
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $activePlan->slug])
|
||||
->call('completePlan')
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPlan::STATUS_COMPLETED, $activePlan->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_archive_plan_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('archivePlan')
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPlan::STATUS_ARCHIVED, $this->plan->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_complete_phase_updates_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->inProgress()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('completePhase', $phase->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPhase::STATUS_COMPLETED, $phase->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_block_phase_updates_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->inProgress()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('blockPhase', $phase->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPhase::STATUS_BLOCKED, $phase->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_skip_phase_updates_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->pending()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('skipPhase', $phase->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPhase::STATUS_SKIPPED, $phase->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_reset_phase_restores_to_pending(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->completed()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('resetPhase', $phase->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPhase::STATUS_PENDING, $phase->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_open_add_task_modal_sets_phase_and_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->pending()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('openAddTaskModal', $phase->id)
|
||||
->assertSet('showAddTaskModal', true)
|
||||
->assertSet('selectedPhaseId', $phase->id)
|
||||
->assertSet('newTaskName', '')
|
||||
->assertSet('newTaskNotes', '');
|
||||
}
|
||||
|
||||
public function test_add_task_requires_task_name(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->pending()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('openAddTaskModal', $phase->id)
|
||||
->set('newTaskName', '')
|
||||
->call('addTask')
|
||||
->assertHasErrors(['newTaskName' => 'required']);
|
||||
}
|
||||
|
||||
public function test_add_task_validates_name_max_length(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$phase = AgentPhase::factory()->pending()->create([
|
||||
'agent_plan_id' => $this->plan->id,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug])
|
||||
->call('openAddTaskModal', $phase->id)
|
||||
->set('newTaskName', str_repeat('x', 256))
|
||||
->call('addTask')
|
||||
->assertHasErrors(['newTaskName' => 'max']);
|
||||
}
|
||||
|
||||
public function test_get_status_color_class_returns_correct_class(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(PlanDetail::class, ['slug' => $this->plan->slug]);
|
||||
$instance = $component->instance();
|
||||
|
||||
$this->assertStringContainsString('blue', $instance->getStatusColorClass(AgentPlan::STATUS_ACTIVE));
|
||||
$this->assertStringContainsString('green', $instance->getStatusColorClass(AgentPlan::STATUS_COMPLETED));
|
||||
$this->assertStringContainsString('red', $instance->getStatusColorClass(AgentPhase::STATUS_BLOCKED));
|
||||
}
|
||||
}
|
||||
165
tests/Feature/Livewire/PlansTest.php
Normal file
165
tests/Feature/Livewire/PlansTest.php
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\Models\AgentPlan;
|
||||
use Core\Mod\Agentic\View\Modal\Admin\Plans;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class PlansTest extends LivewireTestCase
|
||||
{
|
||||
private Workspace $workspace;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
}
|
||||
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(Plans::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->assertSet('search', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('perPage', 15);
|
||||
}
|
||||
|
||||
public function test_search_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->set('search', 'my plan')
|
||||
->assertSet('search', 'my plan');
|
||||
}
|
||||
|
||||
public function test_status_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->set('status', AgentPlan::STATUS_ACTIVE)
|
||||
->assertSet('status', AgentPlan::STATUS_ACTIVE);
|
||||
}
|
||||
|
||||
public function test_workspace_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->set('workspace', (string) $this->workspace->id)
|
||||
->assertSet('workspace', (string) $this->workspace->id);
|
||||
}
|
||||
|
||||
public function test_clear_filters_resets_all_filters(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->set('search', 'test')
|
||||
->set('status', AgentPlan::STATUS_ACTIVE)
|
||||
->set('workspace', (string) $this->workspace->id)
|
||||
->call('clearFilters')
|
||||
->assertSet('search', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('workspace', '');
|
||||
}
|
||||
|
||||
public function test_activate_plan_changes_status_to_active(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$plan = AgentPlan::factory()->draft()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->call('activate', $plan->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPlan::STATUS_ACTIVE, $plan->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_complete_plan_changes_status_to_completed(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$plan = AgentPlan::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->call('complete', $plan->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPlan::STATUS_COMPLETED, $plan->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_archive_plan_changes_status_to_archived(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$plan = AgentPlan::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->call('archive', $plan->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentPlan::STATUS_ARCHIVED, $plan->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_delete_plan_removes_from_database(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$plan = AgentPlan::factory()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
$planId = $plan->id;
|
||||
|
||||
Livewire::test(Plans::class)
|
||||
->call('delete', $planId)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertDatabaseMissing('agent_plans', ['id' => $planId]);
|
||||
}
|
||||
|
||||
public function test_status_options_returns_all_statuses(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Plans::class);
|
||||
|
||||
$options = $component->instance()->statusOptions;
|
||||
|
||||
$this->assertArrayHasKey(AgentPlan::STATUS_DRAFT, $options);
|
||||
$this->assertArrayHasKey(AgentPlan::STATUS_ACTIVE, $options);
|
||||
$this->assertArrayHasKey(AgentPlan::STATUS_COMPLETED, $options);
|
||||
$this->assertArrayHasKey(AgentPlan::STATUS_ARCHIVED, $options);
|
||||
}
|
||||
}
|
||||
160
tests/Feature/Livewire/PlaygroundTest.php
Normal file
160
tests/Feature/Livewire/PlaygroundTest.php
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\Playground;
|
||||
use Livewire\Livewire;
|
||||
|
||||
/**
|
||||
* Tests for the Playground Livewire component.
|
||||
*
|
||||
* Note: This component loads MCP server YAML files and uses Core\Api\Models\ApiKey.
|
||||
* Tests focus on component state and interactions. Server loading gracefully
|
||||
* handles missing registry files by setting an empty servers array.
|
||||
*/
|
||||
class PlaygroundTest extends LivewireTestCase
|
||||
{
|
||||
public function test_renders_successfully(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->assertSet('selectedServer', '')
|
||||
->assertSet('selectedTool', '')
|
||||
->assertSet('arguments', [])
|
||||
->assertSet('response', '')
|
||||
->assertSet('loading', false)
|
||||
->assertSet('apiKey', '')
|
||||
->assertSet('error', null)
|
||||
->assertSet('keyStatus', null)
|
||||
->assertSet('keyInfo', null)
|
||||
->assertSet('tools', []);
|
||||
}
|
||||
|
||||
public function test_mount_loads_servers_gracefully_when_registry_missing(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Playground::class);
|
||||
|
||||
// When registry.yaml does not exist, servers defaults to empty array
|
||||
$this->assertIsArray($component->instance()->servers);
|
||||
}
|
||||
|
||||
public function test_updated_api_key_clears_validation_state(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('keyStatus', 'valid')
|
||||
->set('keyInfo', ['name' => 'Test Key'])
|
||||
->set('apiKey', 'new-key-value')
|
||||
->assertSet('keyStatus', null)
|
||||
->assertSet('keyInfo', null);
|
||||
}
|
||||
|
||||
public function test_validate_key_sets_empty_status_when_key_is_blank(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('apiKey', '')
|
||||
->call('validateKey')
|
||||
->assertSet('keyStatus', 'empty');
|
||||
}
|
||||
|
||||
public function test_validate_key_sets_invalid_for_unknown_key(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('apiKey', 'not-a-real-key-abc123')
|
||||
->call('validateKey')
|
||||
->assertSet('keyStatus', 'invalid');
|
||||
}
|
||||
|
||||
public function test_is_authenticated_returns_true_when_logged_in(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Playground::class);
|
||||
|
||||
$this->assertTrue($component->instance()->isAuthenticated());
|
||||
}
|
||||
|
||||
public function test_is_authenticated_returns_false_when_not_logged_in(): void
|
||||
{
|
||||
// No actingAs - unauthenticated request
|
||||
$component = Livewire::test(Playground::class);
|
||||
|
||||
$this->assertFalse($component->instance()->isAuthenticated());
|
||||
}
|
||||
|
||||
public function test_updated_selected_server_clears_tool_selection(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('selectedTool', 'some_tool')
|
||||
->set('toolSchema', ['name' => 'some_tool'])
|
||||
->set('selectedServer', 'agent-server')
|
||||
->assertSet('selectedTool', '')
|
||||
->assertSet('toolSchema', null);
|
||||
}
|
||||
|
||||
public function test_updated_selected_tool_clears_arguments_and_response(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('arguments', ['key' => 'value'])
|
||||
->set('response', 'previous response')
|
||||
->set('selectedTool', '')
|
||||
->assertSet('toolSchema', null);
|
||||
}
|
||||
|
||||
public function test_execute_does_nothing_when_no_server_selected(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('selectedServer', '')
|
||||
->set('selectedTool', '')
|
||||
->call('execute')
|
||||
->assertSet('loading', false)
|
||||
->assertSet('response', '');
|
||||
}
|
||||
|
||||
public function test_execute_generates_curl_example_without_api_key(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Playground::class)
|
||||
->set('selectedServer', 'agent-server')
|
||||
->set('selectedTool', 'plan_create')
|
||||
->call('execute')
|
||||
->assertSet('loading', false);
|
||||
|
||||
// Without a valid API key, response should show the request format
|
||||
$component = Livewire::test(Playground::class);
|
||||
$component->set('selectedServer', 'agent-server');
|
||||
$component->set('selectedTool', 'plan_create');
|
||||
$component->call('execute');
|
||||
|
||||
$response = $component->instance()->response;
|
||||
if ($response) {
|
||||
$decoded = json_decode($response, true);
|
||||
$this->assertIsArray($decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
tests/Feature/Livewire/RequestLogTest.php
Normal file
87
tests/Feature/Livewire/RequestLogTest.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\RequestLog;
|
||||
use Livewire\Livewire;
|
||||
|
||||
/**
|
||||
* Tests for the RequestLog Livewire component.
|
||||
*
|
||||
* Note: This component queries McpApiRequest from host-uk/core.
|
||||
* Tests focus on component state and interactions that do not
|
||||
* require the mcp_api_requests table to be present.
|
||||
*/
|
||||
class RequestLogTest extends LivewireTestCase
|
||||
{
|
||||
public function test_renders_successfully(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(RequestLog::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(RequestLog::class)
|
||||
->assertSet('serverFilter', '')
|
||||
->assertSet('statusFilter', '')
|
||||
->assertSet('selectedRequestId', null)
|
||||
->assertSet('selectedRequest', null);
|
||||
}
|
||||
|
||||
public function test_server_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(RequestLog::class)
|
||||
->set('serverFilter', 'agent-server')
|
||||
->assertSet('serverFilter', 'agent-server');
|
||||
}
|
||||
|
||||
public function test_status_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(RequestLog::class)
|
||||
->set('statusFilter', 'success')
|
||||
->assertSet('statusFilter', 'success');
|
||||
}
|
||||
|
||||
public function test_close_detail_clears_selection(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(RequestLog::class)
|
||||
->set('selectedRequestId', 5)
|
||||
->call('closeDetail')
|
||||
->assertSet('selectedRequestId', null)
|
||||
->assertSet('selectedRequest', null);
|
||||
}
|
||||
|
||||
public function test_updated_server_filter_triggers_re_render(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
// Setting filter should update the property (pagination resets internally)
|
||||
Livewire::test(RequestLog::class)
|
||||
->set('serverFilter', 'my-server')
|
||||
->assertSet('serverFilter', 'my-server')
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_updated_status_filter_triggers_re_render(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(RequestLog::class)
|
||||
->set('statusFilter', 'failed')
|
||||
->assertSet('statusFilter', 'failed')
|
||||
->assertOk();
|
||||
}
|
||||
}
|
||||
167
tests/Feature/Livewire/SessionDetailTest.php
Normal file
167
tests/Feature/Livewire/SessionDetailTest.php
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\Models\AgentSession;
|
||||
use Core\Mod\Agentic\View\Modal\Admin\SessionDetail;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class SessionDetailTest extends LivewireTestCase
|
||||
{
|
||||
private Workspace $workspace;
|
||||
|
||||
private AgentSession $session;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
$this->session = AgentSession::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id]);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id])
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_mount_loads_session_by_id(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(SessionDetail::class, ['id' => $this->session->id]);
|
||||
|
||||
$this->assertEquals($this->session->id, $component->instance()->session->id);
|
||||
}
|
||||
|
||||
public function test_active_session_has_polling_enabled(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(SessionDetail::class, ['id' => $this->session->id]);
|
||||
|
||||
$this->assertGreaterThan(0, $component->instance()->pollingInterval);
|
||||
}
|
||||
|
||||
public function test_completed_session_disables_polling(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$completedSession = AgentSession::factory()->completed()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
$component = Livewire::test(SessionDetail::class, ['id' => $completedSession->id]);
|
||||
|
||||
$this->assertEquals(0, $component->instance()->pollingInterval);
|
||||
}
|
||||
|
||||
public function test_has_default_modal_states(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id])
|
||||
->assertSet('showCompleteModal', false)
|
||||
->assertSet('showFailModal', false)
|
||||
->assertSet('showReplayModal', false)
|
||||
->assertSet('completeSummary', '')
|
||||
->assertSet('failReason', '');
|
||||
}
|
||||
|
||||
public function test_pause_session_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id])
|
||||
->call('pauseSession')
|
||||
->assertOk();
|
||||
|
||||
$this->assertEquals(AgentSession::STATUS_PAUSED, $this->session->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_resume_session_changes_status_from_paused(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$pausedSession = AgentSession::factory()->paused()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $pausedSession->id])
|
||||
->call('resumeSession')
|
||||
->assertOk();
|
||||
|
||||
$this->assertEquals(AgentSession::STATUS_ACTIVE, $pausedSession->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_open_complete_modal_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id])
|
||||
->call('openCompleteModal')
|
||||
->assertSet('showCompleteModal', true);
|
||||
}
|
||||
|
||||
public function test_open_fail_modal_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id])
|
||||
->call('openFailModal')
|
||||
->assertSet('showFailModal', true);
|
||||
}
|
||||
|
||||
public function test_open_replay_modal_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(SessionDetail::class, ['id' => $this->session->id])
|
||||
->call('openReplayModal')
|
||||
->assertSet('showReplayModal', true);
|
||||
}
|
||||
|
||||
public function test_work_log_returns_array(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(SessionDetail::class, ['id' => $this->session->id]);
|
||||
|
||||
$this->assertIsArray($component->instance()->workLog);
|
||||
}
|
||||
|
||||
public function test_artifacts_returns_array(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(SessionDetail::class, ['id' => $this->session->id]);
|
||||
|
||||
$this->assertIsArray($component->instance()->artifacts);
|
||||
}
|
||||
|
||||
public function test_get_status_color_class_returns_string(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(SessionDetail::class, ['id' => $this->session->id]);
|
||||
|
||||
$class = $component->instance()->getStatusColorClass(AgentSession::STATUS_ACTIVE);
|
||||
|
||||
$this->assertNotEmpty($class);
|
||||
}
|
||||
}
|
||||
202
tests/Feature/Livewire/SessionsTest.php
Normal file
202
tests/Feature/Livewire/SessionsTest.php
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\Models\AgentSession;
|
||||
use Core\Mod\Agentic\View\Modal\Admin\Sessions;
|
||||
use Core\Tenant\Models\Workspace;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class SessionsTest extends LivewireTestCase
|
||||
{
|
||||
private Workspace $workspace;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
}
|
||||
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(Sessions::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->assertSet('search', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('agentType', '')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('planSlug', '')
|
||||
->assertSet('perPage', 20);
|
||||
}
|
||||
|
||||
public function test_search_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->set('search', 'session-abc')
|
||||
->assertSet('search', 'session-abc');
|
||||
}
|
||||
|
||||
public function test_status_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->set('status', AgentSession::STATUS_ACTIVE)
|
||||
->assertSet('status', AgentSession::STATUS_ACTIVE);
|
||||
}
|
||||
|
||||
public function test_agent_type_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->set('agentType', AgentSession::AGENT_SONNET)
|
||||
->assertSet('agentType', AgentSession::AGENT_SONNET);
|
||||
}
|
||||
|
||||
public function test_clear_filters_resets_all_filters(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->set('search', 'test')
|
||||
->set('status', AgentSession::STATUS_ACTIVE)
|
||||
->set('agentType', AgentSession::AGENT_OPUS)
|
||||
->set('workspace', '1')
|
||||
->set('planSlug', 'some-plan')
|
||||
->call('clearFilters')
|
||||
->assertSet('search', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('agentType', '')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('planSlug', '');
|
||||
}
|
||||
|
||||
public function test_pause_session_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$session = AgentSession::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->call('pause', $session->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentSession::STATUS_PAUSED, $session->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_resume_session_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$session = AgentSession::factory()->paused()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->call('resume', $session->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentSession::STATUS_ACTIVE, $session->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_complete_session_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$session = AgentSession::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->call('complete', $session->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentSession::STATUS_COMPLETED, $session->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_fail_session_changes_status(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$session = AgentSession::factory()->active()->create([
|
||||
'workspace_id' => $this->workspace->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Sessions::class)
|
||||
->call('fail', $session->id)
|
||||
->assertDispatched('notify');
|
||||
|
||||
$this->assertEquals(AgentSession::STATUS_FAILED, $session->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_get_status_color_class_returns_green_for_active(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Sessions::class);
|
||||
|
||||
$class = $component->instance()->getStatusColorClass(AgentSession::STATUS_ACTIVE);
|
||||
|
||||
$this->assertStringContainsString('green', $class);
|
||||
}
|
||||
|
||||
public function test_get_status_color_class_returns_red_for_failed(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Sessions::class);
|
||||
|
||||
$class = $component->instance()->getStatusColorClass(AgentSession::STATUS_FAILED);
|
||||
|
||||
$this->assertStringContainsString('red', $class);
|
||||
}
|
||||
|
||||
public function test_get_agent_badge_class_returns_class_for_opus(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Sessions::class);
|
||||
|
||||
$class = $component->instance()->getAgentBadgeClass(AgentSession::AGENT_OPUS);
|
||||
|
||||
$this->assertNotEmpty($class);
|
||||
$this->assertStringContainsString('violet', $class);
|
||||
}
|
||||
|
||||
public function test_status_options_contains_all_statuses(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Sessions::class);
|
||||
$options = $component->instance()->statusOptions;
|
||||
|
||||
$this->assertArrayHasKey(AgentSession::STATUS_ACTIVE, $options);
|
||||
$this->assertArrayHasKey(AgentSession::STATUS_PAUSED, $options);
|
||||
$this->assertArrayHasKey(AgentSession::STATUS_COMPLETED, $options);
|
||||
$this->assertArrayHasKey(AgentSession::STATUS_FAILED, $options);
|
||||
}
|
||||
}
|
||||
173
tests/Feature/Livewire/TemplatesTest.php
Normal file
173
tests/Feature/Livewire/TemplatesTest.php
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\Templates;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class TemplatesTest extends LivewireTestCase
|
||||
{
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(Templates::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->assertSet('category', '')
|
||||
->assertSet('search', '')
|
||||
->assertSet('showPreviewModal', false)
|
||||
->assertSet('showCreateModal', false)
|
||||
->assertSet('showImportModal', false)
|
||||
->assertSet('previewSlug', null)
|
||||
->assertSet('importError', null);
|
||||
}
|
||||
|
||||
public function test_open_preview_sets_slug_and_shows_modal(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->call('openPreview', 'my-template')
|
||||
->assertSet('showPreviewModal', true)
|
||||
->assertSet('previewSlug', 'my-template');
|
||||
}
|
||||
|
||||
public function test_close_preview_hides_modal_and_clears_slug(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->call('openPreview', 'my-template')
|
||||
->call('closePreview')
|
||||
->assertSet('showPreviewModal', false)
|
||||
->assertSet('previewSlug', null);
|
||||
}
|
||||
|
||||
public function test_open_import_modal_shows_modal_with_clean_state(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->call('openImportModal')
|
||||
->assertSet('showImportModal', true)
|
||||
->assertSet('importFileName', '')
|
||||
->assertSet('importPreview', null)
|
||||
->assertSet('importError', null);
|
||||
}
|
||||
|
||||
public function test_close_import_modal_hides_modal_and_clears_state(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->call('openImportModal')
|
||||
->call('closeImportModal')
|
||||
->assertSet('showImportModal', false)
|
||||
->assertSet('importError', null)
|
||||
->assertSet('importPreview', null);
|
||||
}
|
||||
|
||||
public function test_search_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->set('search', 'feature')
|
||||
->assertSet('search', 'feature');
|
||||
}
|
||||
|
||||
public function test_category_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->set('category', 'development')
|
||||
->assertSet('category', 'development');
|
||||
}
|
||||
|
||||
public function test_clear_filters_resets_search_and_category(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->set('search', 'test')
|
||||
->set('category', 'development')
|
||||
->call('clearFilters')
|
||||
->assertSet('search', '')
|
||||
->assertSet('category', '');
|
||||
}
|
||||
|
||||
public function test_get_category_color_returns_correct_class_for_development(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Templates::class);
|
||||
|
||||
$class = $component->instance()->getCategoryColor('development');
|
||||
|
||||
$this->assertStringContainsString('blue', $class);
|
||||
}
|
||||
|
||||
public function test_get_category_color_returns_correct_class_for_maintenance(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Templates::class);
|
||||
|
||||
$class = $component->instance()->getCategoryColor('maintenance');
|
||||
|
||||
$this->assertStringContainsString('green', $class);
|
||||
}
|
||||
|
||||
public function test_get_category_color_returns_correct_class_for_custom(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Templates::class);
|
||||
|
||||
$class = $component->instance()->getCategoryColor('custom');
|
||||
|
||||
$this->assertStringContainsString('zinc', $class);
|
||||
}
|
||||
|
||||
public function test_get_category_color_returns_default_for_unknown(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(Templates::class);
|
||||
|
||||
$class = $component->instance()->getCategoryColor('unknown-category');
|
||||
|
||||
$this->assertNotEmpty($class);
|
||||
}
|
||||
|
||||
public function test_close_create_modal_hides_modal_and_clears_state(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(Templates::class)
|
||||
->set('showCreateModal', true)
|
||||
->set('createTemplateSlug', 'some-template')
|
||||
->call('closeCreateModal')
|
||||
->assertSet('showCreateModal', false)
|
||||
->assertSet('createTemplateSlug', null)
|
||||
->assertSet('createVariables', []);
|
||||
}
|
||||
}
|
||||
119
tests/Feature/Livewire/ToolAnalyticsTest.php
Normal file
119
tests/Feature/Livewire/ToolAnalyticsTest.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\ToolAnalytics;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class ToolAnalyticsTest extends LivewireTestCase
|
||||
{
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(ToolAnalytics::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->assertSet('days', 7)
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('server', '');
|
||||
}
|
||||
|
||||
public function test_set_days_updates_days_property(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->call('setDays', 30)
|
||||
->assertSet('days', 30);
|
||||
}
|
||||
|
||||
public function test_set_days_to_seven(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->call('setDays', 30)
|
||||
->call('setDays', 7)
|
||||
->assertSet('days', 7);
|
||||
}
|
||||
|
||||
public function test_workspace_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->set('workspace', '1')
|
||||
->assertSet('workspace', '1');
|
||||
}
|
||||
|
||||
public function test_server_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->set('server', 'agent-server')
|
||||
->assertSet('server', 'agent-server');
|
||||
}
|
||||
|
||||
public function test_clear_filters_resets_all(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolAnalytics::class)
|
||||
->set('workspace', '1')
|
||||
->set('server', 'agent-server')
|
||||
->call('clearFilters')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('server', '');
|
||||
}
|
||||
|
||||
public function test_get_success_rate_color_class_green_above_95(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ToolAnalytics::class);
|
||||
|
||||
$class = $component->instance()->getSuccessRateColorClass(96.0);
|
||||
|
||||
$this->assertStringContainsString('green', $class);
|
||||
}
|
||||
|
||||
public function test_get_success_rate_color_class_amber_between_80_and_95(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ToolAnalytics::class);
|
||||
|
||||
$class = $component->instance()->getSuccessRateColorClass(85.0);
|
||||
|
||||
$this->assertStringContainsString('amber', $class);
|
||||
}
|
||||
|
||||
public function test_get_success_rate_color_class_red_below_80(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ToolAnalytics::class);
|
||||
|
||||
$class = $component->instance()->getSuccessRateColorClass(70.0);
|
||||
|
||||
$this->assertStringContainsString('red', $class);
|
||||
}
|
||||
}
|
||||
148
tests/Feature/Livewire/ToolCallsTest.php
Normal file
148
tests/Feature/Livewire/ToolCallsTest.php
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Core\Mod\Agentic\Tests\Feature\Livewire;
|
||||
|
||||
use Core\Mod\Agentic\View\Modal\Admin\ToolCalls;
|
||||
use Livewire\Livewire;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
/**
|
||||
* Tests for the ToolCalls Livewire component.
|
||||
*
|
||||
* Note: This component queries McpToolCall from host-uk/core.
|
||||
* Tests focus on component state, filters, and actions that do not
|
||||
* depend on the mcp_tool_calls table being present.
|
||||
*/
|
||||
class ToolCallsTest extends LivewireTestCase
|
||||
{
|
||||
public function test_requires_hades_access(): void
|
||||
{
|
||||
$this->expectException(HttpException::class);
|
||||
|
||||
Livewire::test(ToolCalls::class);
|
||||
}
|
||||
|
||||
public function test_renders_successfully_with_hades_user(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_has_default_property_values(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->assertSet('search', '')
|
||||
->assertSet('server', '')
|
||||
->assertSet('tool', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('agentType', '')
|
||||
->assertSet('perPage', 25)
|
||||
->assertSet('selectedCallId', null);
|
||||
}
|
||||
|
||||
public function test_search_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->set('search', 'plan_create')
|
||||
->assertSet('search', 'plan_create');
|
||||
}
|
||||
|
||||
public function test_server_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->set('server', 'agent-server')
|
||||
->assertSet('server', 'agent-server');
|
||||
}
|
||||
|
||||
public function test_status_filter_updates(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->set('status', 'success')
|
||||
->assertSet('status', 'success');
|
||||
}
|
||||
|
||||
public function test_view_call_sets_selected_call_id(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->call('viewCall', 42)
|
||||
->assertSet('selectedCallId', 42);
|
||||
}
|
||||
|
||||
public function test_close_call_detail_clears_selection(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->call('viewCall', 42)
|
||||
->call('closeCallDetail')
|
||||
->assertSet('selectedCallId', null);
|
||||
}
|
||||
|
||||
public function test_clear_filters_resets_all(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
Livewire::test(ToolCalls::class)
|
||||
->set('search', 'test')
|
||||
->set('server', 'server-1')
|
||||
->set('tool', 'plan_create')
|
||||
->set('status', 'success')
|
||||
->set('workspace', '1')
|
||||
->set('agentType', 'opus')
|
||||
->call('clearFilters')
|
||||
->assertSet('search', '')
|
||||
->assertSet('server', '')
|
||||
->assertSet('tool', '')
|
||||
->assertSet('status', '')
|
||||
->assertSet('workspace', '')
|
||||
->assertSet('agentType', '');
|
||||
}
|
||||
|
||||
public function test_get_status_badge_class_returns_green_for_success(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ToolCalls::class);
|
||||
|
||||
$class = $component->instance()->getStatusBadgeClass(true);
|
||||
|
||||
$this->assertStringContainsString('green', $class);
|
||||
}
|
||||
|
||||
public function test_get_status_badge_class_returns_red_for_failure(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ToolCalls::class);
|
||||
|
||||
$class = $component->instance()->getStatusBadgeClass(false);
|
||||
|
||||
$this->assertStringContainsString('red', $class);
|
||||
}
|
||||
|
||||
public function test_get_agent_badge_class_returns_string(): void
|
||||
{
|
||||
$this->actingAsHades();
|
||||
|
||||
$component = Livewire::test(ToolCalls::class);
|
||||
|
||||
$this->assertNotEmpty($component->instance()->getAgentBadgeClass('opus'));
|
||||
$this->assertNotEmpty($component->instance()->getAgentBadgeClass('sonnet'));
|
||||
$this->assertNotEmpty($component->instance()->getAgentBadgeClass('unknown'));
|
||||
}
|
||||
}
|
||||
36
tests/Fixtures/HadesUser.php
Normal file
36
tests/Fixtures/HadesUser.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Fixtures;
|
||||
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
|
||||
/**
|
||||
* Fake user fixture for Livewire component tests.
|
||||
*
|
||||
* Satisfies the isHades() check used by all admin components.
|
||||
*/
|
||||
class HadesUser extends Authenticatable
|
||||
{
|
||||
protected $fillable = ['id', 'name', 'email'];
|
||||
|
||||
protected $table = 'users';
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public function isHades(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function defaultHostWorkspace(): ?object
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getAuthIdentifier(): mixed
|
||||
{
|
||||
return $this->attributes['id'] ?? 1;
|
||||
}
|
||||
}
|
||||
1
tests/views/admin/api-keys.blade.php
Normal file
1
tests/views/admin/api-keys.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="api-keys"></div>
|
||||
1
tests/views/admin/dashboard.blade.php
Normal file
1
tests/views/admin/dashboard.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="dashboard"></div>
|
||||
1
tests/views/admin/plan-detail.blade.php
Normal file
1
tests/views/admin/plan-detail.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="plan-detail"></div>
|
||||
1
tests/views/admin/plans.blade.php
Normal file
1
tests/views/admin/plans.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="plans"></div>
|
||||
1
tests/views/admin/playground.blade.php
Normal file
1
tests/views/admin/playground.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="playground"></div>
|
||||
1
tests/views/admin/session-detail.blade.php
Normal file
1
tests/views/admin/session-detail.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="session-detail"></div>
|
||||
1
tests/views/admin/sessions.blade.php
Normal file
1
tests/views/admin/sessions.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="sessions"></div>
|
||||
1
tests/views/admin/templates.blade.php
Normal file
1
tests/views/admin/templates.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="templates"></div>
|
||||
1
tests/views/admin/tool-analytics.blade.php
Normal file
1
tests/views/admin/tool-analytics.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="tool-analytics"></div>
|
||||
1
tests/views/admin/tool-calls.blade.php
Normal file
1
tests/views/admin/tool-calls.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="tool-calls"></div>
|
||||
1
tests/views/mcp/admin/api-key-manager.blade.php
Normal file
1
tests/views/mcp/admin/api-key-manager.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="api-key-manager"></div>
|
||||
1
tests/views/mcp/admin/playground.blade.php
Normal file
1
tests/views/mcp/admin/playground.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="playground"></div>
|
||||
1
tests/views/mcp/admin/request-log.blade.php
Normal file
1
tests/views/mcp/admin/request-log.blade.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div data-testid="request-log"></div>
|
||||
Loading…
Add table
Reference in a new issue