Files
landingpage-haus-schleusingen/tests/Views/LayoutA11yTest.php

120 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Views;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
/**
* Static a11y checks for the shared layout
* (`app/views/layouts/main.php`). We verify the layout's *source*
* carries the right ARIA / landmark attributes rather than spinning
* up the full render (which would need nav, OG, structured-data,
* server-vars, and a dozen more locals). The home view is tested
* for content-level a11y in `HomeViewA11yTest`.
*/
final class LayoutA11yTest extends TestCase
{
private string $layoutSource;
protected function setUp(): void
{
$path = dirname(__DIR__, 2) . '/app/views/layouts/main.php';
self::assertFileExists($path);
$this->layoutSource = (string) file_get_contents($path);
self::assertNotEmpty($this->layoutSource);
}
#[Test]
public function htmlRootCarriesLangAttribute(): void
{
// The layout emits <html lang="..."> with the value rendered by PHP from
// the $locale variable (not literally `$locale` between quotes).
// We assert the source binds lang to the $locale variable inside PHP output.
self::assertStringContainsString('<html lang="', $this->layoutSource);
self::assertStringContainsString('$locale', $this->layoutSource);
// Make sure $locale actually flows into the lang attribute (basic
// co-occurrence check on the same <html ...> opening tag).
self::assertMatchesRegularExpression(
'~<html\b[^>]*\blang=[^>]*\$locale~s',
$this->layoutSource,
'Layout must bind <html lang> to the current locale'
);
}
#[Test]
public function skipLinkPointsAtMain(): void
{
self::assertStringContainsString('class="skip-link"', $this->layoutSource);
self::assertStringContainsString('href="#main"', $this->layoutSource);
}
#[Test]
public function mainLandmarkHasIdAndAriaLabel(): void
{
self::assertMatchesRegularExpression(
'/<main\b[^>]*\bid="main"/',
$this->layoutSource
);
self::assertMatchesRegularExpression(
'/<main\b[^>]*\baria-label=/',
$this->layoutSource
);
}
#[Test]
public function navLandmarkHasAriaLabel(): void
{
self::assertMatchesRegularExpression(
'/<nav\b[^>]*\baria-label=/',
$this->layoutSource
);
}
#[Test]
public function footerHasRoleAndLabel(): void
{
self::assertMatchesRegularExpression(
'/<footer\b[^>]*\baria-label=/',
$this->layoutSource
);
}
#[Test]
public function lightboxIsADialogModal(): void
{
self::assertStringContainsString('id="lightbox"', $this->layoutSource);
self::assertStringContainsString('role="dialog"', $this->layoutSource);
self::assertStringContainsString('aria-modal="true"', $this->layoutSource);
}
#[Test]
public function lightboxImageCarriesAltAttribute(): void
{
self::assertMatchesRegularExpression(
'/<img\b[^>]*\bid="lightboxImg"[^>]*\balt=/',
$this->layoutSource
);
}
#[Test]
public function localeSwitcherHostIsAriaLabeled(): void
{
// The LocaleSwitcher widget uses aria-label on its <ul>.
self::assertStringContainsString('aria-label="', $this->layoutSource);
}
#[Test]
public function mobileNavToggleIsKeyboardAccessible(): void
{
self::assertMatchesRegularExpression(
'/<button\b[^>]*\bclass="nav-hamburger"/',
$this->layoutSource
);
self::assertStringContainsString('aria-expanded=', $this->layoutSource);
self::assertStringContainsString('aria-controls=', $this->layoutSource);
}
}