renders++; } public function render(): string { return <<<'BLADE'

confirming: {{ var_export($confirming, true) }}

deleting: {{ var_export($deletingId, true) }}

renders: {{ $renders }}

BLADE; } } class CollapseProbe extends Component { public bool $fineTuning = false; public int $renders = 0; public function touch(): void { $this->renders++; } public function expand(): void { $this->fineTuning = true; } public function collapse(): void { $this->fineTuning = false; } public function render(): string { return <<<'BLADE'

fine tuning: {{ var_export($fineTuning, true) }}

renders: {{ $renders }}

Zones and paces.

advanced:

Everything else.
BLADE; } } function collapseProbe() { Livewire::component('collapse-probe', CollapseProbe::class); Route::middleware('web')->get('/collapse-probe', fn () => Blade::render(<<<'BLADE' @vite(config('livewire-material.showcase.vite')) @livewireStyles @livewireScripts BLADE)); return visit('/collapse-probe')->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } function overlayProbe() { Livewire::component('overlay-probe', OverlayProbe::class); Route::middleware('web')->get('/overlay-probe', fn () => Blade::render(<<<'BLADE' @vite(config('livewire-material.showcase.vite')) @livewireStyles @livewireScripts BLADE)); return visit('/overlay-probe')->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } function containment() { return visit('/material/containment')->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } it('writes back what closed means: false for a flag, null for an id', function () { $page = overlayProbe(); $page->click('button:has-text("Confirm")') ->assertScript("[...document.querySelectorAll('dialog')].some((d) => d.open && d.textContent.includes('Are you sure?'))"); $page->click('dialog[open] button:has-text("Re-render")') ->assertSeeIn('#renders', '1') ->assertScript("[...document.querySelectorAll('dialog')].some((d) => d.open && d.textContent.includes('Are you sure?'))"); $page->keys('dialog[open] button:has-text("Re-render")', 'Escape') ->assertScript("! [...document.querySelectorAll('dialog')].some((d) => d.open)") ->assertSeeIn('#confirming', 'false'); $page->click('button:has-text("Delete 7")') ->assertSeeIn('#deleting', '7') ->assertScript("[...document.querySelectorAll('dialog')].some((d) => d.open && d.textContent.includes('Delete share?'))"); $page->script("document.querySelector('dialog[open]').dispatchEvent(new Event('cancel', { cancelable: true }))"); $page->assertSeeIn('#deleting', 'NULL'); }); it('closes a showcase dialog on Escape and gives focus back to its trigger', function () { // Opened from the keyboard: Safari does not focus a button on click, so after a click there // is nothing for the dialog to hand focus back to. $page = containment(); $page->script("[...document.querySelectorAll('#containment button')].find((b) => b.textContent.trim() === 'Basic dialog').focus()"); $page->keys(':focus', 'Enter') ->assertScript("document.querySelector('#containment dialog').open"); $page->keys('#containment dialog[open] button:has-text("Cancel")', 'Escape') ->assertScript("! document.querySelector('#containment dialog').open") ->assertScript("document.activeElement.textContent.trim() === 'Basic dialog'"); }); it('slides a side sheet in, traps the page, and closes on the scrim', function () { $sheet = "document.querySelector('#containment aside[role=\"dialog\"]')"; $page = containment() ->click('#containment button:has-text("Side sheet")') ->assertScript("getComputedStyle({$sheet}).display !== 'none'") ->assertScript("document.querySelector('header').closest('[aria-hidden=\"true\"]') !== null"); // This sheet's own scrim: the standard side sheet above it on the page is a `[data-sheet]` too. $page->script("{$sheet}.parentElement.querySelector(':scope > [aria-hidden=\"true\"]').click()"); $page->assertScript("getComputedStyle({$sheet}).display === 'none'") ->assertScript("document.querySelector('header').closest('[aria-hidden=\"true\"]') === null"); }); it('dismisses a bottom sheet dragged down past a quarter of its height', function () { $sheet = "document.querySelector('#containment section[role=\"dialog\"]')"; $page = containment() ->click('#containment button:has(> span:text-is("Bottom sheet"))') ->assertScript("getComputedStyle({$sheet}).display !== 'none'") ->wait(0.5); $page->script(<< { const handle = {$sheet}.querySelector('[data-drag-handle]'); const box = handle.getBoundingClientRect(); const x = box.x + box.width / 2, y = box.y + box.height / 2; handle.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, clientX: x, clientY: y, button: 0 })); window.dispatchEvent(new PointerEvent('pointermove', { clientX: x, clientY: y + 400 })); window.dispatchEvent(new PointerEvent('pointerup', { clientX: x, clientY: y + 400 })); })() JS); $page->assertScript("getComputedStyle({$sheet}).display === 'none'"); }); it('opens a row\'s opener from a press anywhere on the row, but not from its own buttons', function () { $page = containment(); $row = '#containment [data-card][data-list-row]:not([data-list-actionable])'; $page->script("window.__opened = 0; document.querySelector('{$row} [data-list-open]').addEventListener('click', (event) => { event.preventDefault(); window.__opened++ })"); $page->click("{$row} p") ->assertScript('window.__opened === 1'); $page->click("{$row} button:has-text(\"Copy link\")") ->assertScript('window.__opened === 1'); }); it('makes a directly actionable card the one tab stop, answering Enter', function () { $card = '#containment [data-card][data-list-actionable]'; $page = containment(); $page->script("window.__opened = 0; document.querySelector('{$card} [data-list-open]').addEventListener('click', (event) => { event.preventDefault(); window.__opened++ })"); $page->script("document.querySelector('{$card}').focus()"); $page->assertScript("document.activeElement.matches('{$card}')"); $page->keys($card, 'Enter') ->assertScript('window.__opened === 1'); }); it('binds a collapse to a Livewire property both ways', function () { $collapse = "document.querySelector('#fine-tuning-collapse')"; $page = collapseProbe() ->assertScript("{$collapse}.open === false"); $page->click('#fine-tuning-collapse summary') ->assertScript("{$collapse}.open === true") ->click('button:has-text("Re-render")') ->assertSeeIn('#renders', '1') ->assertSeeIn('#fine-tuning', 'true') ->assertScript("{$collapse}.open === true"); $page->click('button:has-text("Close from the server")') ->assertSeeIn('#fine-tuning', 'false') ->assertScript("{$collapse}.open === false"); $page->click('button:has-text("Open from the server")') ->assertSeeIn('#fine-tuning', 'true') ->assertScript("{$collapse}.open === true"); }); it('binds a collapse to an Alpine property both ways', function () { $collapse = "document.querySelector('#advanced-collapse')"; $page = collapseProbe() ->assertScript("{$collapse}.open === false"); $page->click('#advanced-collapse summary') ->assertScript("{$collapse}.open === true") ->assertSeeIn('#advanced', 'true'); $page->click('button:has-text("Close from Alpine")') ->assertSeeIn('#advanced', 'false') ->assertScript("{$collapse}.open === false"); });