lthn.io/app/Core/Tests/Feature/AdminComponentsTest.php
Claude 41a90cbff8
feat: lthn.io API serving live chain data
Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.

Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 17:17:42 +01:00

341 lines
10 KiB
PHP

<?php
/*
* Core PHP Framework
*
* Licensed under the European Union Public Licence (EUPL) v1.2.
* See LICENSE file for details.
*/
declare(strict_types=1);
/**
* Admin Component Tests
*
* Tests for the admin UI pattern library components.
* These components provide data-driven, reusable UI elements for Hades admin pages.
*/
use Illuminate\Support\Facades\Blade;
use Illuminate\View\Compilers\BladeCompiler;
use Illuminate\View\Component;
uses()->group('admin-components');
describe('Admin Manager Table Component', function () {
it('renders table with columns and rows', function () {
$columns = ['Name', 'Email', 'Status'];
$rows = [
['John Doe', 'john@example.com', 'Active'],
['Jane Smith', 'jane@example.com', 'Pending'],
];
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" />', [
'columns' => $columns,
'rows' => $rows,
]);
expect($html)
->toContain('Name')
->toContain('Email')
->toContain('Status')
->toContain('John Doe')
->toContain('john@example.com')
->toContain('Jane Smith');
});
it('renders empty state when no rows', function () {
$columns = ['Name', 'Email'];
$rows = [];
$empty = 'No users found.';
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" :empty="$empty" />', [
'columns' => $columns,
'rows' => $rows,
'empty' => $empty,
]);
expect($html)->toContain('No users found.');
});
it('renders bold cell type', function () {
$columns = ['Name'];
$rows = [
[['bold' => 'Important Name']],
];
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" />', [
'columns' => $columns,
'rows' => $rows,
]);
expect($html)
->toContain('Important Name')
->toContain('font-medium');
});
it('renders badge cell type', function () {
$columns = ['Status'];
$rows = [
[['badge' => 'Active', 'color' => 'green']],
];
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" />', [
'columns' => $columns,
'rows' => $rows,
]);
expect($html)
->toContain('Active')
->toContain('rounded-full');
});
it('renders multi-line cells', function () {
$columns = ['User'];
$rows = [
[['lines' => [
['bold' => 'John Doe'],
['muted' => 'john@example.com'],
]]],
];
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" />', [
'columns' => $columns,
'rows' => $rows,
]);
expect($html)
->toContain('John Doe')
->toContain('john@example.com');
});
it('renders action buttons', function () {
$columns = ['Name', 'Actions'];
$rows = [
[
'Test Item',
['actions' => [
['icon' => 'pencil', 'click' => 'edit(1)', 'title' => 'Edit'],
['icon' => 'trash', 'click' => 'delete(1)', 'confirm' => 'Are you sure?'],
]],
],
];
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" />', [
'columns' => $columns,
'rows' => $rows,
]);
expect($html)
->toContain('wire:click="edit(1)"')
->toContain('wire:click="delete(1)"')
->toContain('wire:confirm="Are you sure?"');
});
it('supports column alignment', function () {
$columns = [
'Name',
['label' => 'Count', 'align' => 'right'],
['label' => 'Actions', 'align' => 'center'],
];
$rows = [['Test', '10', 'Action']];
$html = Blade::render('<admin:manager-table :columns="$columns" :rows="$rows" />', [
'columns' => $columns,
'rows' => $rows,
]);
expect($html)
->toContain('text-right')
->toContain('text-center');
});
});
describe('Admin Flash Component', function () {
it('renders success message from session', function () {
session()->flash('message', 'Operation successful!');
$html = Blade::render('<admin:flash />');
expect($html)
->toContain('Operation successful!')
->toContain('bg-green-100');
});
it('renders error message from session', function () {
session()->flash('error', 'Something went wrong!');
$html = Blade::render('<admin:flash />');
expect($html)
->toContain('Something went wrong!')
->toContain('bg-red-100');
});
it('renders nothing when no session messages', function () {
session()->forget(['message', 'error']);
$html = Blade::render('<admin:flash />');
expect(trim($html))->toBe('');
});
it('supports custom session keys', function () {
session()->flash('custom_key', 'Custom message');
$html = Blade::render('<admin:flash key="custom_key" />');
expect($html)->toContain('Custom message');
});
});
describe('Admin Filter Bar Component', function () {
it('renders with default 4 columns', function () {
$html = Blade::render('<admin:filter-bar><div>Filter content</div></admin:filter-bar>');
expect($html)
->toContain('sm:grid-cols-4')
->toContain('Filter content');
});
it('renders with custom column count', function () {
$html = Blade::render('<admin:filter-bar cols="3"><div>Content</div></admin:filter-bar>');
expect($html)->toContain('sm:grid-cols-3');
});
it('renders with 2 columns', function () {
$html = Blade::render('<admin:filter-bar cols="2"><div>Content</div></admin:filter-bar>');
expect($html)->toContain('sm:grid-cols-2');
});
it('renders with 5 columns', function () {
$html = Blade::render('<admin:filter-bar cols="5"><div>Content</div></admin:filter-bar>');
expect($html)->toContain('sm:grid-cols-5');
});
});
describe('Admin Search Component', function () {
it('renders search input', function () {
$html = Blade::render('<admin:search />');
expect($html)
->toContain('type="text"')
->toContain('magnifying-glass');
});
it('renders with custom placeholder', function () {
$html = Blade::render('<admin:search placeholder="Search users..." />');
expect($html)->toContain('placeholder="Search users..."');
});
it('renders with wire:model binding', function () {
$html = Blade::render('<admin:search model="searchTerm" />');
expect($html)->toContain('wire:model.live.debounce.300ms="searchTerm"');
});
});
describe('Admin Filter Component', function () {
it('renders select with placeholder', function () {
$html = Blade::render('<admin:filter placeholder="All Items" />');
expect($html)
->toContain('<select')
->toContain('All Items');
});
it('renders with array options', function () {
$options = [
'active' => 'Active',
'pending' => 'Pending',
'inactive' => 'Inactive',
];
$html = Blade::render('<admin:filter :options="$options" />', [
'options' => $options,
]);
expect($html)
->toContain('value="active"')
->toContain('Active')
->toContain('value="pending"')
->toContain('Pending');
});
it('renders with collection options', function () {
$options = collect([
(object) ['id' => 1, 'name' => 'Option 1'],
(object) ['id' => 2, 'name' => 'Option 2'],
]);
$html = Blade::render('<admin:filter :options="$options" />', [
'options' => $options,
]);
expect($html)
->toContain('value="1"')
->toContain('Option 1')
->toContain('value="2"')
->toContain('Option 2');
});
it('renders with wire:model binding', function () {
$html = Blade::render('<admin:filter model="statusFilter" />');
expect($html)->toContain('wire:model.live="statusFilter"');
});
it('renders with label', function () {
$html = Blade::render('<admin:filter label="Status" />');
expect($html)
->toContain('Status')
->toContain('All Statuss'); // Auto-pluralised placeholder
});
});
describe('Admin Component Integration', function () {
it('all admin blade components compile without errors', function () {
$componentsPath = base_path('app/Core/Front/Admin/Blade/components');
$files = glob("{$componentsPath}/*.blade.php");
expect($files)->not->toBeEmpty('No admin components found');
$errors = [];
foreach ($files as $file) {
try {
$compiler = app(BladeCompiler::class);
$compiler->compile($file);
} catch (Throwable $e) {
$errors[] = [
'file' => basename($file),
'error' => $e->getMessage(),
];
}
}
if (! empty($errors)) {
$message = "Admin components failed to compile:\n";
foreach ($errors as $error) {
$message .= " - {$error['file']}: {$error['error']}\n";
}
$this->fail($message);
}
expect($errors)->toBeEmpty();
});
it('admin components are registered with correct namespace', function () {
// Check that admin: prefix resolves
$viewFactory = app('view');
// The admin: namespace should be registered
$namespaces = $viewFactory->getFinder()->getHints();
expect($namespaces)->toHaveKey('admin');
});
});