diff --git a/tests/Browser/BarsTest.php b/tests/Browser/BarsTest.php index db577655..1a08f147 100644 --- a/tests/Browser/BarsTest.php +++ b/tests/Browser/BarsTest.php @@ -9,6 +9,17 @@ class BarsProbe extends Component { public string $tab = 'files'; + public string $deferredTab = 'files'; + + public int $deferredUpdates = 0; + + // Only runs while the server processes a request that carries $deferredTab along — never on + // the click alone, since a plain wire:model (no `.live`) only changes it locally until then. + public function updatedDeferredTab(): void + { + $this->deferredUpdates++; + } + public function render(): string { return <<<'BLADE' @@ -27,6 +38,13 @@ class BarsProbe extends Component Two downloads. +

deferred tab: {{ $deferredTab }}, updates: {{ $deferredUpdates }}

+ + + Deferred files. + Deferred people. + + @@ -36,7 +54,7 @@ class BarsProbe extends Component - +
@@ -89,6 +107,30 @@ it('moves between tabs with the arrow keys, skipping disabled ones, and tells Li ->assertSeeIn('#tab', 'activity'); }); +it('sends a request per click with wire:model.live, but nothing until then with plain wire:model', function () { + // updatedDeferredTab() on the probe only runs while the server processes a request that + // carries $deferredTab with it — never from the click alone — so its counter (not a browser + // network hook, which a plain property commit does not reliably fire) tells whether a click + // reached the server at all. + $page = barsProbe(); + + // Plain wire:model is entangled locally: the click switches the panel and its aria-selected at + // once, but the property itself only reaches the server on the next request from anything else. + $page->click('#deferred-people') + ->assertScript("document.querySelector('#deferred-people').getAttribute('aria-selected') === 'true'") + ->assertSee('Deferred people.') + ->assertSeeIn('#deferred-tab', 'files') + ->assertSeeIn('#deferred-updates', '0'); + + // wire:model.live sends its own request, which carries the deferred property above along with + // it — the one request updates both. + $page->click('#share-people') + ->assertSeeIn('#tab', 'people') + ->assertSeeIn('#deferred-tab', 'people') + ->assertSeeIn('#deferred-updates', '1') + ->assertNoJavaScriptErrors(); +}); + it('collapses a medium app bar into its row as the page scrolls, and fades its small title in', function () { $headline = "getComputedStyle(document.querySelector('#bar [data-md-app-bar-row] [data-md-app-bar-headline]')).opacity"; @@ -146,6 +188,15 @@ it('turns section tabs into a picker on a phone', function () { ->assertScript("! document.querySelector('[data-md-section-nav-picker] [role=\"menuitem\"][href=\"#security\"]').hasAttribute('aria-current')"); }); +it('shares the row width equally between the section nav\'s items, whatever their label', function () { + $widths = "[...document.querySelectorAll('[data-md-section-nav] [data-md-tabs-bar] > li')].map((li) => Math.round(li.getBoundingClientRect().width))"; + + barsProbe() + ->assertScript("{$widths}.length === 3") + ->assertScript("new Set({$widths}).size === 1") + ->assertNoJavaScriptErrors(); +}); + class AppBarOverflowProbe extends Component { public int $stars = 0; @@ -217,7 +268,7 @@ it('shows the app bar overflow at exactly 599 and 600px', function () { it('moves the keyboard through an app bar\'s overflow menu, and closes it once the width no longer shows it', function () { $page = appBarOverflowProbe()->resize(599, 800); - $page->click('#bar [data-md-app-bar-overflow="compact"] button') + $page->click('#bar [data-md-app-bar-overflow="compact"] [data-md-menu-trigger] button') ->assertScript("document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')") ->keys(':focus', 'ArrowDown') ->assertScript("document.activeElement.textContent.includes('Star')") @@ -226,9 +277,12 @@ it('moves the keyboard through an app bar\'s overflow menu, and closes it once t ->keys(':focus', 'Escape') ->assertScript("! document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')"); + // Past the reopen guard of the Escape above (menu.js), so the click below is on its own. + $page->wait(0.3); + // Reopen it, then resize across 600px: the compact menu's trigger is no longer shown, so the // menu it opened closes rather than staying open anchored to nothing. - $page->click('#bar [data-md-app-bar-overflow="compact"] button') + $page->click('#bar [data-md-app-bar-overflow="compact"] [data-md-menu-trigger] button') ->assertScript("document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')") ->resize(900, 800) ->assertScript("! document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')") @@ -242,7 +296,7 @@ it('runs a wire:click action from either the icon button or its overflow menu it ->assertSeeIn('#stars', '1'); $page->resize(599, 800) - ->click('#bar [data-md-app-bar-overflow="compact"] button') + ->click('#bar [data-md-app-bar-overflow="compact"] [data-md-menu-trigger] button') ->click('[role="menuitem"]:has-text("Star")') ->assertSeeIn('#stars', '2'); });