synor/apps/explorer-web/e2e/accessibility.spec.ts
Gulshan Yadav 48949ebb3f Initial commit: Synor blockchain monorepo
A complete blockchain implementation featuring:
- synord: Full node with GHOSTDAG consensus
- explorer-web: Modern React blockchain explorer with 3D DAG visualization
- CLI wallet and tools
- Smart contract SDK and example contracts (DEX, NFT, token)
- WASM crypto library for browser/mobile
2026-01-08 05:22:17 +05:30

72 lines
2.5 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Accessibility', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('skip link is focusable and works', async ({ page }) => {
// Tab to focus skip link
await page.keyboard.press('Tab');
// Skip link should be visible when focused
const skipLink = page.getByRole('link', { name: /skip to main content/i });
await expect(skipLink).toBeFocused();
await expect(skipLink).toBeVisible();
// Click skip link
await skipLink.click();
// Focus should move to main content
const main = page.locator('#main-content');
await expect(main).toBeFocused();
});
test('all interactive elements are keyboard accessible', async ({ page }) => {
// Tab through the page and ensure focusable elements receive focus
let focusedElements = 0;
for (let i = 0; i < 20; i++) {
await page.keyboard.press('Tab');
const focused = await page.evaluate(() => document.activeElement?.tagName);
if (focused && ['A', 'BUTTON', 'INPUT'].includes(focused)) {
focusedElements++;
}
}
// Should have multiple focusable elements
expect(focusedElements).toBeGreaterThan(5);
});
test('pagination has correct aria attributes', async ({ page }) => {
await page.goto('/blocks');
// Check pagination nav has correct role
const pagination = page.getByRole('navigation', { name: /pagination/i });
await expect(pagination).toBeVisible();
// Current page should have aria-current
const currentPage = page.locator('[aria-current="page"]');
await expect(currentPage).toBeVisible();
});
test('copy buttons have proper labels', async ({ page }) => {
await page.goto('/blocks');
// Click first block to go to detail
const firstBlock = page.locator('a[href^="/block/"]').first();
await firstBlock.click();
// Copy button should have accessible label
const copyButton = page.getByRole('button', { name: /copy/i }).first();
await expect(copyButton).toBeVisible();
await expect(copyButton).toHaveAttribute('aria-label', /copy/i);
});
test('connection status announces changes', async ({ page }) => {
// Connection status should have aria-live
const connectionStatus = page.locator('[aria-live="polite"]').filter({ hasText: /live|offline|connecting/i });
await expect(connectionStatus).toBeVisible();
await expect(connectionStatus).toHaveAttribute('aria-live', 'polite');
});
});