waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } function focused(string $expression): string { return "document.activeElement.{$expression}"; } it('opens a menu on the first item and walks it with the keyboard', function () { $page = showcase() ->assertNoJavaScriptErrors() ->click(MORE) ->assertAttribute(MORE, 'aria-expanded', 'true') ->assertScript(focused("textContent.trim().startsWith('Copy link')")); $page->keys(':focus', ['ArrowDown', 'ArrowDown']) ->assertScript(focused("textContent.trim().startsWith('Rename')")); $page->keys(':focus', 'End') ->assertScript(focused("textContent.trim().startsWith('Delete')")); $page->keys(':focus', 'ArrowDown') ->assertScript(focused("textContent.trim().startsWith('Copy link')")); $page->keys(':focus', 'd') ->assertScript(focused("textContent.trim().startsWith('Download')")); $page->keys(':focus', 'Escape') ->assertAttribute(MORE, 'aria-expanded', 'false') ->assertScript(focused("getAttribute('aria-label') === 'More'")); }); it('opens a menu from the keyboard, on the last item with ArrowUp', function () { $page = showcase(); $page->script("document.querySelector('".MORE."').focus()"); $page->keys(':focus', 'ArrowUp') ->assertAttribute(MORE, 'aria-expanded', 'true') ->assertScript(focused("textContent.trim().startsWith('Delete')")); }); it('opens a menu the moment the page can be used', function () { // The guard against a light-dismiss press reopening the menu once measured from the page's // time origin, and swallowed every click in the first quarter second. visit('/material') ->click(MORE) ->assertAttribute(MORE, 'aria-expanded', 'true'); }); it('closes a menu when an item is chosen, but not one that keeps it open', function () { $page = showcase(); $page->click(MORE) ->click('#menus [role="menuitem"]:has-text("Download")') ->assertAttribute(MORE, 'aria-expanded', 'false'); $page->click('#menus button:has-text("Sort")') ->click('#menus [role="menuitemcheckbox"]:has-text("Largest")') ->assertScript("document.querySelector('#menus [role=\"menu\"][aria-label=\"Sort\"]').matches(':popover-open')"); }); it('shows a tooltip on keyboard focus and hides it on Escape', function () { $tooltip = "document.querySelector('#buttons [aria-label=\"Tonal\"] [popover]')"; $page = showcase(); // A key press first, so the browser is in keyboard modality, as a keyboard user would be — // Firefox only counts a scripted focus as :focus-visible after one. Then focused directly // rather than tabbed to: WebKit, like Safari on macOS, leaves buttons out of the Tab order // unless full keyboard access is on. $page->keys('body', 'Tab'); $page->script("document.querySelector('#buttons [aria-label=\"Tonal\"]').focus()"); $page->assertScript(focused("getAttribute('aria-label') === 'Tonal'")) ->assertScript("{$tooltip}.matches(':popover-open')"); $page->keys(':focus', 'Escape') ->assertScript("! {$tooltip}.matches(':popover-open')"); }); it('moves a connected group\'s choice with the arrow keys', function () { $checked = fn (string $value): string => "document.querySelector('#buttons input[name=\"showcase-theme\"][value=\"{$value}\"]').checked"; $page = showcase(); $page->script("document.querySelector('#buttons input[name=\"showcase-theme\"][value=\"system\"]').focus()"); $page->keys(':focus', 'ArrowLeft') ->assertScript($checked('dark')) ->assertScript("getComputedStyle(document.querySelector('#buttons input[value=\"dark\"]').parentElement).borderTopLeftRadius === '9999px'"); }); it('rounds a split button\'s trailing half while its menu is open', function () { $trailing = "document.querySelector('[data-split=\"trailing\"]')"; showcase() ->click('[data-split="trailing"] >> nth=0') ->assertScript("{$trailing}.getAttribute('aria-expanded') === 'true'") ->assertScript("getComputedStyle({$trailing}).borderTopLeftRadius === '9999px'"); }); it('turns the FAB into a close button while its menu is open', function () { $fab = "document.querySelector('button[aria-label=\"New\"]')"; $page = showcase() ->click('button[aria-label="New"]') ->assertScript("{$fab}.getAttribute('aria-expanded') === 'true'") ->assertScript(focused("textContent.trim() === 'Upload files'")); $page->keys(':focus', 'Escape') ->assertScript("{$fab}.getAttribute('aria-expanded') === 'false'") ->assertScript(focused("getAttribute('aria-label') === 'New'")); }); it('animates the loading indicator in the browser', function () { $clock = "document.querySelector('#buttons [role=\"progressbar\"] svg').getCurrentTime()"; showcase()->assertScript("{$clock} > 0.1"); });