Files
livewire-material/tests/Feature/Components/TabsTest.php
T
Andreas Reinhold / reiniandClaude Opus 5 f90695cedd
tests / browser (chrome, chromium) (push) Successful in 3m34s
tests / browser (safari, webkit) (push) Successful in 6m2s
tests / lint (push) Successful in 59s
tests / feature (8.4) (push) Successful in 1m6s
tests / feature (8.5) (push) Successful in 1m9s
tests / browser (firefox, firefox) (push) Successful in 4m20s
Add app bars, toolbars, tabs and the account and theme controls
M3 Expressive top app bars (small, centered, medium and large flexible,
search) that collapse with CSS sticky, docked and floating toolbars,
primary and secondary tabs with a view-transition indicator, section
navigation, the account menu and theme toggles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
2026-09-13 08:26:54 +02:00

83 lines
3.8 KiB
PHP

<?php
use Livewire\Component;
use Livewire\Livewire;
it('renders the tablist on the server with the first enabled tab chosen', function () {
$html = (string) $this->blade(<<<'BLADE'
<x-tabs id="share" :tabs="[['name' => 'files', 'label' => 'Files', 'disabled' => true], ['name' => 'people', 'label' => 'People', 'icon' => 'group', 'badge' => 3]]">
<x-tab name="people">Anna</x-tab>
</x-tabs>
BLADE);
expect($html)
->toContain('role="tablist"')
->toContain('data-variant="primary"')
->toContain('id="share-people"')
->toContain('aria-controls="share-people-panel"')
->toMatch('/data-tab="people"\s+aria-controls="share-people-panel"\s+aria-selected="true"\s+tabindex="0"/')
->toMatch('/data-tab="files"\s+aria-controls="share-files-panel"\s+aria-selected="false"\s+tabindex="-1"/')
->toContain('disabled')
->toContain('data-tab-indicator')
->toContain('--tabs-indicator: share-indicator')
->toContain('x-modelable="selected"')
->toContain('role="tabpanel"')
->toContain('>3</span>');
});
it('takes a variant, stacks icons and scrolls on request', function () {
expect((string) $this->blade('<x-tabs variant="secondary" stacked scrollable :tabs="[[\'name\' => \'a\', \'label\' => \'A\']]" />'))
->toContain('data-variant="secondary"')
->not->toContain('data-stacked')
->toContain('data-scrollable')
->and((string) $this->blade('<x-tabs stacked selected="b" :tabs="[[\'name\' => \'a\', \'label\' => \'A\'], [\'name\' => \'b\', \'label\' => \'B\']]" />'))
->toContain('data-stacked')
->toMatch('/data-tab="b"\s+aria-controls="[^"]+"\s+aria-selected="true"/');
});
it('entangles the chosen tab with Livewire and renders the one the property names', function () {
Livewire::component('tabs-probe', new class extends Component
{
public string $tab = 'people';
public function render(): string
{
return '<div><x-tabs wire:model.live="tab" :tabs="[[\'name\' => \'files\', \'label\' => \'Files\'], [\'name\' => \'people\', \'label\' => \'People\']]" /></div>';
}
});
expect(Livewire::test('tabs-probe')->html())
->toContain(".entangle('tab').live")
->not->toContain('x-modelable')
->toMatch('/data-tab="people"\s+aria-controls="[^"]+"\s+aria-selected="true"/');
});
it('draws section navigation as secondary tabs and a picker', function () {
$html = (string) $this->blade(<<<'BLADE'
<x-section-nav label="Settings" :items="[
['title' => 'Profile', 'icon' => 'person', 'url' => '/settings/profile'],
['title' => 'Security', 'icon' => 'lock', 'url' => '/settings/security', 'active' => true, 'badge' => 1],
]" />
BLADE);
expect($html)
->toContain('aria-label="Settings"')
->toContain('data-section-picker')
->toContain('data-variant="secondary"')
->toContain('sm:flex')
->toMatch('/href="\/settings\/security"\s+data-tab\s+aria-current="page"\s+wire:navigate/')
->not->toMatch('/href="\/settings\/profile"\s+data-tab\s+aria-current/')
->toContain('role="menuitemcheckbox"');
});
it('marks the section whose url is the request\'s, and wraps many sections onto a grid', function () {
$this->get('/');
$items = collect(range(1, 7))->map(fn (int $n): array => ['title' => "S{$n}", 'url' => $n === 3 ? url('/') : "/s/{$n}"])->all();
expect((string) $this->blade('<x-section-nav :items="$items" no-wire-navigate />', ['items' => $items]))
->toContain('sm:grid sm:grid-cols-4 xl:flex')
->toMatch('/data-tab\s+aria-current="page"\s*>\s*<span data-tab-content>\s*<span class="truncate">S3/')
->not->toContain('wire:navigate');
});