inDarkMode() : $page->inLightMode(); return $page->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && document.querySelector('[data-md-error-page]') !== null"); } /** * Whether the element's computed background is the colour a role resolves to on this page. */ function paintedIn(string $selector, string $role): string { return << { const probe = document.createElement('div'); probe.style.backgroundColor = 'var(--md-sys-color-{$role})'; document.body.append(probe); const expected = getComputedStyle(probe).backgroundColor; probe.remove(); return expected !== 'rgba(0, 0, 0, 0)' && getComputedStyle(document.querySelector('{$selector}')).backgroundColor === expected; })() JS; } it('draws the 404 page in the scheme, in light and dark', function () { missingPage('light') ->assertSee('Page not found') ->assertVisible('[data-md-error-headline]') ->assertScript("document.documentElement.getAttribute('data-theme') === 'light'") ->assertScript(paintedIn('body', 'surface')) ->assertScript("getComputedStyle(document.querySelector('[data-md-error-shape] svg')).color !== getComputedStyle(document.body).color") ->assertNoJavaScriptErrors(); missingPage('dark') ->assertScript("document.documentElement.getAttribute('data-theme') === 'dark'") ->assertScript(paintedIn('body', 'surface')) ->assertScript("getComputedStyle(document.body).backgroundColor !== 'rgb(253, 247, 254)'"); }); it('fits a 400px screen without scrolling sideways', function () { missingPage() ->resize(400, 800) ->assertVisible('[data-md-error-headline]') ->assertScript('document.documentElement.scrollWidth <= window.innerWidth') ->assertScript("document.querySelector('[data-md-error-actions] a').getBoundingClientRect().right <= 400"); }); /** * Plan step 40: the fallback path, the same server serving the request `LaravelHttpServer` runs * in-process, so a config change here reaches it exactly as it reaches a Feature test's client — * an empty temporary directory has no `build/manifest.json` and no `hot` file, so `ErrorPage::assets()` * throws and returns null (tests/Feature/ErrorPagesTest.php does the same for the HTTP client). */ it('draws the button and the shape from the inlined fallback stylesheet, and repaints in dark mode', function () { $public = sys_get_temp_dir().'/livewire-material-fallback-'.Str::random(8); File::ensureDirectoryExists($public); $originalPublicPath = app()->publicPath(); app()->usePublicPath($public); Vite::useHotFile($public.'/hot'); try { missingPage('light') ->assertScript("document.querySelector('style[data-md-error-fallback]') !== null") ->assertScript("document.querySelector('link[href*=\"/build/\"]') === null") // The button: button.css's round, filled shape, not a bare unstyled . ->assertScript("getComputedStyle(document.querySelector('[data-md-button]')).borderRadius !== '0px'") ->assertScript(paintedIn('[data-md-button][data-md-variant=filled]', 'primary')) // The shape: shape.css's sizing and the primary-container tint error-page.css paints its svg with. ->assertScript("getComputedStyle(document.querySelector('[data-md-error-shape] svg')).color !== getComputedStyle(document.body).color") ->assertScript(paintedIn('body', 'surface')) ->assertNoJavaScriptErrors(); // The [data-theme='dark'] block the fallback also inlines repaints the page, exactly as the // built stylesheet does for the test above. missingPage('dark') ->assertScript("document.documentElement.getAttribute('data-theme') === 'dark'") ->assertScript(paintedIn('body', 'surface')) ->assertScript("getComputedStyle(document.body).backgroundColor !== 'rgb(253, 247, 254)'"); } finally { app()->usePublicPath($originalPublicPath); Vite::useHotFile($originalPublicPath.'/hot'); File::deleteDirectory($public); } }); /** * Plan step 46: an application's own build, which imports the stylesheets its views render and so * never `error-page.css` — SealShare's didn't, and its error pages drew a shape filling the window * with the headline unstyled in a corner. The probe build here is the foundation and the Workbench's * scheme and nothing else, so everything the layout draws must come from the rules the page inlines * beside the application's ``. */ it('draws the layout from its own inlined rules under a build that never imports them', function () { $public = sys_get_temp_dir().'/livewire-material-build-'.Str::random(8); File::ensureDirectoryExists($public.'/build/assets'); // The foundation and the scheme, as an application's bundle would carry them; without the font // face, whose relative url would 404 from here and is no part of what this test proves. $css = Stylesheets::bundle([ realpath(__DIR__.'/../../resources/css/foundation.css'), workbench_path('resources/css/material-scheme.css'), ]); File::put($public.'/build/assets/app-probe.css', (string) preg_replace('/@font-face\s*\{[^}]*\}/', '', $css)); File::put($public.'/build/manifest.json', json_encode([ 'resources/css/app.css' => ['file' => 'assets/app-probe.css', 'src' => 'resources/css/app.css', 'isEntry' => true], ])); $originalPublicPath = app()->publicPath(); $originalVite = config('livewire-material.showcase.vite'); app()->usePublicPath($public); Vite::useHotFile($public.'/hot'); config(['livewire-material.showcase.vite' => ['resources/css/app.css']]); try { missingPage('light') ->resize(1280, 800) ->assertScript("document.querySelector('link[href*=\"/build/assets/app-probe.css\"]') !== null") ->assertScript("document.querySelector('style[data-md-error-styles]') !== null") ->assertScript("document.querySelector('style[data-md-error-fallback]') === null") // The layout: a centred column, the art at its 240px from medium, not a shape filling the window. ->assertScript("getComputedStyle(document.querySelector('[data-md-error-page]')).display === 'flex'") ->assertScript("Math.round(document.querySelector('[data-md-error-art]').getBoundingClientRect().width) === 240") ->assertScript("document.querySelector('[data-md-error-shape] svg').getBoundingClientRect().width <= 240") ->assertScript("(() => { const r = document.querySelector('[data-md-error-headline]').getBoundingClientRect(); return Math.abs((r.left + r.right) / 2 - window.innerWidth / 2) <= 2; })()") // The button and shape rules the layout imports, and the scheme from the application's build. ->assertScript("getComputedStyle(document.querySelector('[data-md-button]')).borderRadius !== '0px'") ->assertScript(paintedIn('[data-md-button][data-md-variant=filled]', 'primary')) ->assertScript(paintedIn('body', 'surface')) ->assertNoJavaScriptErrors(); } finally { config(['livewire-material.showcase.vite' => $originalVite]); app()->usePublicPath($originalPublicPath); Vite::useHotFile($originalPublicPath.'/hot'); File::deleteDirectory($public); } });