Files
livewire-material/tests/Feature/Components/ButtonGroupTest.php
T
Andreas Reinhold / reiniandClaude Opus 5 b8c6d411db Draw the connected choice group without Tailwind
Plan step 36. <x-group> renders data-md-group with its size, variant,
shape, multiple and inline, a data-md-button-group row and
data-md-group-segment labels over its radios or checkboxes. group.css
draws the segments as M3's buttons with the toggle button's colours
from :has(:checked), the disabled treatment from :has(:disabled), the
focus ring from :has(:focus-visible) and the 48px target at xs and sm.

The connected shapes move into button-group.css (the corner scale,
square ends, the pressed and selected inner corners), which group.css
imports; <x-button-group> adopts them in its own rewrite. The group's
render tests move to GroupTest; AppBarTest (navigation group) follows
the new legend and row hooks of theme-toggle's rows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-14 14:56:59 +02:00

91 lines
4.1 KiB
PHP

<?php
use Livewire\Component;
use Livewire\Livewire;
it('groups buttons with the spacing of their size', function () {
expect((string) $this->blade('<x-button-group label="Views" size="md"><x-button label="Day" /></x-button-group>'))
->toContain('role="group"')
->toContain('aria-label="Views"')
->toContain('data-button-group="standard"')
->toContain('data-size="md"')
->toContain('gap-2')
->and((string) $this->blade('<x-button-group><x-button label="Day" /></x-button-group>'))
->toContain('gap-3');
});
it('connects buttons 2px apart', function () {
expect((string) $this->blade('<x-button-group connected><x-button label="Day" /></x-button-group>'))
->toContain('data-button-group="connected"')
->toContain('gap-0.5');
});
it('squares a group', function () {
// M3 lists "Default shape | Round, square" as a button-group configuration; the shape covers
// every button in the group, so it need not be written on each one.
expect((string) $this->blade('<x-button-group shape="square"><x-button label="Day" /></x-button-group>'))
->toContain('data-shape="square"')
->and((string) $this->blade('<x-button-group connected shape="square"><x-button label="Day" /></x-button-group>'))
->toContain('data-button-group="connected"')
->toContain('data-shape="square"')
->and((string) $this->blade('<x-button-group><x-button label="Day" /></x-button-group>'))
->toContain('data-shape="round"');
});
it('takes over aria-pressed for a group that carries a selection', function () {
$html = (string) $this->blade('<x-button-group connected selection="single" required label="View"><x-button label="Day" value="day" :selected="true" /></x-button-group>');
expect($html)
->toContain('data-selection="single"')
->toContain('data-selection-required')
->toContain('multiple: false')
->toContain('required: true')
->toContain('value: null')
->toContain('x-on:click="press($event)"')
// No model: the group takes the state from the buttons' own aria-pressed and goes on.
->toContain('x-modelable="value"')
->and((string) $this->blade('<x-button-group connected selection="multi"><x-button label="Bold" value="bold" :selected="false" /></x-button-group>'))
->toContain('multiple: true')
->toContain('required: false')
->toContain('value: []')
->and((string) $this->blade('<x-button-group connected><x-button label="Day" /></x-button-group>'))
->not->toContain('data-selection')
->not->toContain('press($event)');
});
it('entangles a selection group with the property it binds, and keeps wire:model off the div', function () {
$component = new class extends Component
{
public string $view = 'week';
public function render(): string
{
return <<<'BLADE'
<div>
<x-button-group connected selection="single" required wire:model.live="view" label="View">
<x-button label="Day" value="day" :selected="$view === 'day'" />
<x-button label="Week" value="week" :selected="$view === 'week'" />
</x-button-group>
</div>
BLADE;
}
};
$html = Livewire::test($component)->assertSet('view', 'week')->html();
expect($html)
->toContain('data-selection="single"')
->toMatch('/value: window\.Livewire\.find\(/')
->and(substr_count($html, 'wire:model.live="view"'))->toBe(0);
});
it('never wraps a group onto a second line', function () {
expect((string) $this->blade('<x-button-group><x-button label="Day" /></x-button-group>'))
->not->toContain('flex-wrap');
});
it('marks icon buttons, which keep their width when a group is pressed', function () {
expect((string) $this->blade('<x-button icon="format_bold" aria-label="Bold" />'))->toContain('data-md-icon-button')
->and((string) $this->blade('<x-button label="Bold" />'))->not->toContain('data-md-icon-button');
});