get(route('home')); $response->assertOk(); $response->assertSee('href="#main-content"', escape: false); $response->assertSee('class="skip-link"', escape: false); $response->assertSee('data-test="skip-to-content"', escape: false); }); test('authenticated dashboard has skip link', function () { $user = User::factory()->client()->create(); $response = $this->actingAs($user)->get(route('client.dashboard')); $response->assertOk(); $response->assertSee('href="#main-content"', escape: false); $response->assertSee('class="skip-link"', escape: false); }); test('admin dashboard has skip link', function () { $admin = User::factory()->admin()->create(); $response = $this->actingAs($admin)->get(route('admin.dashboard')); $response->assertOk(); $response->assertSee('href="#main-content"', escape: false); $response->assertSee('class="skip-link"', escape: false); }); test('login page has skip link', function () { $response = $this->get(route('login')); $response->assertOk(); $response->assertSee('href="#main-content"', escape: false); $response->assertSee('class="skip-link"', escape: false); }); test('skip link uses translation key', function () { session(['locale' => 'en']); $response = $this->get(route('home')); $response->assertOk(); $response->assertSee('Skip to main content'); }); test('skip link shows Arabic translation', function () { session(['locale' => 'ar']); $response = $this->get(route('home')); $response->assertOk(); $response->assertSee('تخطي إلى المحتوى الرئيسي'); }); }); describe('Main Content Landmark', function () { test('public pages have main content landmark', function () { $response = $this->get(route('home')); $response->assertOk(); $response->assertSee('id="main-content"', escape: false); $response->assertSee('role="main"', escape: false); }); test('authenticated pages have main content landmark', function () { $user = User::factory()->client()->create(); $response = $this->actingAs($user)->get(route('client.dashboard')); $response->assertOk(); $response->assertSee('id="main-content"', escape: false); $response->assertSee('role="main"', escape: false); }); test('admin pages have main content landmark', function () { $admin = User::factory()->admin()->create(); $response = $this->actingAs($admin)->get(route('admin.dashboard')); $response->assertOk(); $response->assertSee('id="main-content"', escape: false); $response->assertSee('role="main"', escape: false); }); test('auth pages have main content landmark', function () { $response = $this->get(route('login')); $response->assertOk(); $response->assertSee('id="main-content"', escape: false); $response->assertSee('role="main"', escape: false); }); test('main content has tabindex for focus management', function () { $response = $this->get(route('home')); $response->assertOk(); $response->assertSee('tabindex="-1"', escape: false); }); }); describe('Focus Styles CSS', function () { test('global focus-visible styles are defined', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain(':focus-visible'); expect($cssContent)->toContain('outline-2'); expect($cssContent)->toContain('outline-offset-2'); expect($cssContent)->toContain('outline-accent'); }); test('skip-link class is defined in CSS', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('.skip-link'); expect($cssContent)->toContain('sr-only'); expect($cssContent)->toContain('focus:not-sr-only'); expect($cssContent)->toContain('focus:absolute'); expect($cssContent)->toContain('focus:start-4'); // RTL-compatible }); }); describe('Reduced Motion Preferences', function () { test('reduced motion media query is defined', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('@media (prefers-reduced-motion: reduce)'); expect($cssContent)->toContain('animation-duration: 0.01ms !important'); expect($cssContent)->toContain('animation-iteration-count: 1 !important'); expect($cssContent)->toContain('transition-duration: 0.01ms !important'); }); test('scroll-behavior is included in reduced motion', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('scroll-behavior: auto !important'); }); }); describe('Translation Files', function () { test('English accessibility translations exist', function () { $translations = require lang_path('en/accessibility.php'); expect($translations)->toBeArray(); expect($translations)->toHaveKey('skip_to_content'); expect($translations['skip_to_content'])->toBe('Skip to main content'); }); test('Arabic accessibility translations exist', function () { $translations = require lang_path('ar/accessibility.php'); expect($translations)->toBeArray(); expect($translations)->toHaveKey('skip_to_content'); expect($translations['skip_to_content'])->toBe('تخطي إلى المحتوى الرئيسي'); }); }); describe('Layout File Accessibility', function () { test('sidebar layout has skip link and main landmark', function () { $content = file_get_contents(resource_path('views/components/layouts/app/sidebar.blade.php')); expect($content)->toContain('href="#main-content"'); expect($content)->toContain('class="skip-link"'); expect($content)->toContain('id="main-content"'); expect($content)->toContain('role="main"'); expect($content)->toContain("__('accessibility.skip_to_content')"); }); test('public layout has skip link and main landmark', function () { $content = file_get_contents(resource_path('views/components/layouts/public.blade.php')); expect($content)->toContain('href="#main-content"'); expect($content)->toContain('class="skip-link"'); expect($content)->toContain('id="main-content"'); expect($content)->toContain('role="main"'); expect($content)->toContain("__('accessibility.skip_to_content')"); }); test('auth simple layout has skip link and main landmark', function () { $content = file_get_contents(resource_path('views/components/layouts/auth/simple.blade.php')); expect($content)->toContain('href="#main-content"'); expect($content)->toContain('class="skip-link"'); expect($content)->toContain('id="main-content"'); expect($content)->toContain('role="main"'); expect($content)->toContain("__('accessibility.skip_to_content')"); }); test('auth card layout has skip link and main landmark', function () { $content = file_get_contents(resource_path('views/components/layouts/auth/card.blade.php')); expect($content)->toContain('href="#main-content"'); expect($content)->toContain('class="skip-link"'); expect($content)->toContain('id="main-content"'); expect($content)->toContain('role="main"'); expect($content)->toContain("__('accessibility.skip_to_content')"); }); test('auth split layout has skip link and main landmark', function () { $content = file_get_contents(resource_path('views/components/layouts/auth/split.blade.php')); expect($content)->toContain('href="#main-content"'); expect($content)->toContain('class="skip-link"'); expect($content)->toContain('id="main-content"'); expect($content)->toContain('role="main"'); expect($content)->toContain("__('accessibility.skip_to_content')"); }); }); describe('RTL Accessibility Support', function () { test('skip link uses RTL-compatible positioning', function () { $cssContent = file_get_contents(resource_path('css/app.css')); // Should use focus:start-4 not focus:left-4 for RTL compatibility expect($cssContent)->toContain('focus:start-4'); }); test('skip link appears in correct position for Arabic', function () { session(['locale' => 'ar']); $response = $this->get(route('home')); $response->assertOk(); $response->assertSee('تخطي إلى المحتوى الرئيسي'); }); test('skip link appears in correct position for English', function () { session(['locale' => 'en']); $response = $this->get(route('home')); $response->assertOk(); $response->assertSee('Skip to main content'); }); }); describe('WCAG Color Contrast', function () { test('primary color (Charcoal) is defined in theme', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('--color-primary: #4A4A42'); }); test('accent color (Warm Gray) is defined in theme', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('--color-accent: #C9C4BA'); }); test('background color (Off-White) is defined', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('--color-background: #E8E4DC'); }); test('text color (Deep Black) is defined', function () { $cssContent = file_get_contents(resource_path('css/app.css')); expect($cssContent)->toContain('--color-text: #1A1A1A'); }); test('backward-compatible color aliases exist', function () { $cssContent = file_get_contents(resource_path('css/app.css')); // Legacy color names should be aliased to new colors expect($cssContent)->toContain('--color-navy: var(--color-primary)'); expect($cssContent)->toContain('--color-gold: var(--color-accent)'); expect($cssContent)->toContain('--color-cream: var(--color-background)'); expect($cssContent)->toContain('--color-charcoal: var(--color-text)'); }); });