libra/tests/Feature/AccessibilityComplianceTest...

267 lines
9.9 KiB
PHP

<?php
use App\Models\User;
describe('Skip Link Functionality', function () {
test('public pages have skip to content link', function () {
$response = $this->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-gold');
});
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('gold color is defined in theme', function () {
$cssContent = file_get_contents(resource_path('css/app.css'));
expect($cssContent)->toContain('--color-gold: #D4AF37');
});
test('navy color is defined in theme', function () {
$cssContent = file_get_contents(resource_path('css/app.css'));
expect($cssContent)->toContain('--color-navy: #0A1F44');
});
test('cream background color is defined', function () {
$cssContent = file_get_contents(resource_path('css/app.css'));
expect($cssContent)->toContain('--color-cream: #F9F7F4');
});
test('charcoal text color is defined', function () {
$cssContent = file_get_contents(resource_path('css/app.css'));
expect($cssContent)->toContain('--color-charcoal: #2C3E50');
});
});