Files
ppeasy_vg12/tests/Unit/Plugins/PluginContractTest.php
T
2026-10-09 08:21:06 +02:00

166 lines
4.2 KiB
PHP

<?php
use App\Models\User;
use App\Support\Sidebar\Item;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Vanguard\Plugins\Contracts\Slot;
use Vanguard\Plugins\Plugin;
use Vanguard\Plugins\Vanguard;
use Vanguard\Plugins\Widget;
uses(RefreshDatabase::class);
afterEach(function () {
Vanguard::$slots = [];
Vanguard::$widgets = [];
});
test('slot handlers are registered per position', function () {
Vanguard::$slots = [];
$this->assertFalse(Vanguard::hasSlot('navbar:items'));
Vanguard::slot('navbar:items', FakeSlot::class);
$this->assertTrue(Vanguard::hasSlot('navbar:items'));
$this->assertSame([FakeSlot::class], Vanguard::slotHandlers('navbar:items'));
});
test('multiple handlers may share a position', function () {
Vanguard::$slots = [];
Vanguard::slot('navbar:items', FakeSlot::class);
Vanguard::slot('navbar:items', OtherFakeSlot::class);
$this->assertCount(2, Vanguard::slotHandlers('navbar:items'));
});
test('registering the same handler twice keeps a single entry', function () {
Vanguard::$slots = [];
// Handlers are declared as class names, so a repeat only ever means the
// service provider booted again: under Octane, or between tests, where the
// static registry outlives the container. Appending would render the slot
// once per boot.
Vanguard::slot('navbar:items', FakeSlot::class);
Vanguard::slot('navbar:items', FakeSlot::class);
$this->assertSame([FakeSlot::class], Vanguard::slotHandlers('navbar:items'));
});
test('registering the same widget twice keeps a single entry', function () {
Vanguard::$widgets = [];
Vanguard::widgets([new FakeWidget]);
Vanguard::widgets([new FakeWidget]);
$this->assertCount(1, Vanguard::availableWidgets(User::factory()->create()));
});
test('resolving a slot returns component and props', function () {
Vanguard::$slots = [];
Vanguard::slot('user:show', FakeSlot::class);
$this->assertSame([
[
'component' => 'fake::Component',
'props' => ['greeting' => 'hello world'],
],
], Vanguard::resolveSlot('user:show', ['greeting' => 'hello world']));
});
test('resolving an unregistered slot returns an empty array', function () {
Vanguard::$slots = [];
$this->assertSame([], Vanguard::resolveSlot('nope:nothing'));
});
test('widget serialises to component props and width', function () {
$widget = new FakeWidget;
$this->assertSame([
'component' => 'fake::Widget',
'props' => ['count' => 7],
'width' => '4',
], $widget->toArray());
});
test('widget without permissions authorizes everyone', function () {
$user = User::factory()->create();
$this->assertTrue((new FakeWidget)->authorize($user));
});
test('widget permissions may be a closure', function () {
$user = User::factory()->create();
$widget = (new FakeWidget)->permissions(fn () => false);
$this->assertFalse($widget->authorize($user));
});
test('plugin declares no assets by default', function () {
$plugin = new FakePlugin($this->app);
$this->assertSame([], $plugin->assets());
});
test('registry collects assets from plugins that declare them', function () {
Vanguard::$plugins = [
FakePlugin::class => new FakePlugin($this->app),
FakePluginWithAssets::class => new FakePluginWithAssets($this->app),
];
$this->assertSame(
[['js' => '/vendor/plugins/fake/plugin.js']],
Vanguard::assets()
);
});
class FakeSlot implements Slot
{
public function component(): string
{
return 'fake::Component';
}
public function data(array $context = []): array
{
return ['greeting' => $context['greeting'] ?? null];
}
}
class OtherFakeSlot extends FakeSlot {}
class FakeWidget extends Widget
{
public ?string $width = '4';
public function component(): string
{
return 'fake::Widget';
}
public function data(): array
{
return ['count' => 7];
}
}
class FakePlugin extends Plugin
{
public function sidebar(): ?Item
{
return null;
}
}
class FakePluginWithAssets extends Plugin
{
public function assets(): array
{
return ['js' => '/vendor/plugins/fake/plugin.js'];
}
}