Перейти к основному содержимому
    Назад к блогу
    РазработкаОпубликовано 27 октября 2026 г.

    Как тестировать доступность: автоматика, ручная проверка и чеклист

    Что находят автоматические инструменты и что нет, тесты с jest-axe и Playwright, ручная проверка за 15 минут, команды скринридеров и чеклист перед релизом

    Как тестировать доступность: автоматика, ручная проверка и чеклист

    Часть 8 из 8 серии «Доступный веб на практике». Предыдущая часть: Доступность в React: id, фокус при смене маршрута и объявления.

    Автоматические проверки находят чуть больше половины проблем доступности. В заключительной части серии — как выстроить проверку в три слоя, что проверять руками за 15 минут и чеклист, который стоит пройти перед каждым релизом.

    Как тестировать

    Автоматика: нужна, но недостаточна

    Автоматические инструменты находят не всё. Deque, авторы движка axe-core, проанализировали данные аудитов (более 13 000 страниц и почти 300 000 проблем) и получили, что автоматические тесты выявили 57,4% проблем по количеству (Deque). Остальное — смысл alt-текста, логичность порядка фокуса, понятность ошибок, поведение виджетов — требует человека.

    Поэтому разумная схема — три слоя: линтер при написании кода, автоматические тесты в CI, ручная проверка ключевых сценариев.

    Инструменты в браузере:

    • Lighthouse (встроен в Chrome DevTools) — быстрая оценка, проверяет подмножество правил axe;
    • axe DevTools — расширение от Deque, подробнее Lighthouse;
    • WAVE — расширение от WebAIM, наглядно показывает проблемы прямо на странице;
    • Accessibility panel в DevTools — дерево доступности, вычисленные имена и роли.

    Юнит-тесты. Testing Library подталкивает к доступности сама: запросы getByRole и getByLabelText находят элементы так же, как скринридер. Если тест не может найти кнопку через getByRole('button', { name: 'Отправить' }) — её не найдёт и пользователь.

    // Vitest/Jest + Testing Library + jest-axe
    import { render, screen } from '@testing-library/react';
    import userEvent from '@testing-library/user-event';
    import { axe, toHaveNoViolations } from 'jest-axe';
    import { expect, test } from 'vitest';
    import { ContactForm } from './ContactForm';
    
    expect.extend(toHaveNoViolations);
    
    test('форма не содержит нарушений axe', async () => {
      const { container } = render(<ContactForm />);
      expect(await axe(container)).toHaveNoViolations();
    });
    
    test('ошибка связана с полем и фокус уходит к нему', async () => {
      const user = userEvent.setup();
      render(<ContactForm />);
    
      await user.click(screen.getByRole('button', { name: 'Отправить' }));
    
      const email = screen.getByLabelText('Электронная почта');
      expect(email).toHaveAttribute('aria-invalid', 'true');
      expect(email).toHaveAccessibleDescription(/символ @/);
      expect(email).toHaveFocus();
    });
    

    (toHaveAccessibleDescription и toHaveFocus — из @testing-library/jest-dom.)

    End-to-end. Проверка целых страниц в Playwright с @axe-core/playwright:

    import { test, expect } from '@playwright/test';
    import AxeBuilder from '@axe-core/playwright';
    
    test('главная страница без нарушений WCAG A/AA', async ({ page }) => {
      await page.goto('/');
      const results = await new AxeBuilder({ page })
        .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
        .analyze();
      expect(results.violations).toEqual([]);
    });
    
    test('модальное окно: фокус внутри, Esc закрывает, фокус возвращается', async ({ page }) => {
      await page.goto('/');
      const opener = page.getByRole('button', { name: 'Записаться на консультацию' });
      await opener.click();
    
      const dialog = page.getByRole('dialog', { name: 'Запись на консультацию' });
      await expect(dialog).toBeVisible();
      await expect(dialog.getByLabel('Имя')).toBeFocused();
    
      await page.keyboard.press('Escape');
      await expect(dialog).toBeHidden();
      await expect(opener).toBeFocused();
    });
    

    Ручная проверка за 15 минут

    Для каждого ключевого сценария (оформить заказ, оставить заявку, найти контакты):

    1. Только клавиатура. Пройдите сценарий без мыши. Виден ли фокус на каждом шаге? Логичен ли порядок? Нет ли ловушек? Открываются и закрываются ли меню и модалки?
    2. Масштаб 200% и 400%. Ничего не наезжает, нет горизонтальной прокрутки, ничего не обрезано.
    3. Структура. Посмотрите список заголовков и ориентиров (расширение или ротор скринридера) — понятна ли страница по ним одним?
    4. Скринридер. Пройдите сценарий хотя бы одним скринридером. Минимальный набор команд:
    VoiceOver (macOS) NVDA (Windows)
    Включить Cmd + F5 Ctrl + Alt + N
    Следующий элемент Ctrl + Option + → ↓
    Следующий заголовок Ctrl + Option + Cmd + H H
    Список элементов (ротор) Ctrl + Option + U Insert + F7
    Активировать Ctrl + Option + Space Enter

    Задавайте себе вопросы: у каждого элемента понятное имя? Объявляются ли изменения (ошибки, добавление в корзину)? Понятно ли, где я нахожусь?

    1. Режимы отображения. Включите prefers-reduced-motion, forced-colors и тёмную тему через эмуляцию в DevTools (Rendering).

    Тестируйте с людьми

    Ни один чеклист не заменит пользователя, который каждый день работает со скринридером или голосовым управлением. Если продукт важный — включите таких людей в юзабилити-тестирование.

    Чеклист перед релизом

    Структура и семантика

    • <html lang="..."> указан, фрагменты на другом языке размечены
    • Уникальный <title> на каждой странице
    • Ориентиры: header, nav (подписаны, если их несколько), main (один), footer
    • Заголовки отражают структуру, уровни не пропущены
    • Кнопки — <button>, ссылки — <a href>; нет кликабельных div

    Изображения и медиа

    • У информативных изображений осмысленный alt, у декоративных — alt=""
    • У кнопок и ссылок с иконками есть доступное имя
    • У видео есть субтитры, у аудио — расшифровка; нет автовоспроизведения со звуком

    Формы

    • У каждого поля видимая <label>, связанная с полем
    • Группы радиокнопок и флажков — в fieldset + legend
    • autocomplete у полей с личными данными
    • Ошибки: текстом рядом с полем, aria-invalid, aria-describedby, фокус на первую ошибку
    • Вставка в поля пароля и кода разрешена

    Клавиатура и фокус

    • Весь сценарий проходится клавиатурой, ловушек нет
    • Фокус всегда видим и контрастен; нет outline: none без замены
    • Есть ссылка «Перейти к содержимому»
    • Липкие элементы не перекрывают фокус (scroll-padding-top)
    • Модальные окна: фокус внутри, Esc закрывает, фокус возвращается
    • Нет tabindex больше 0

    Визуальное

    • Контраст текста ≥ 4,5 : 1 (крупного ≥ 3 : 1), компонентов и фокуса ≥ 3 : 1
    • Информация не передаётся только цветом
    • Страница читается при 320 px ширины и масштабе 200–400%
    • Масштабирование не запрещено в meta viewport
    • Учтены prefers-reduced-motion и forced-colors
    • Цели нажатия ≥ 24×24 px (лучше 44×44 на мобильных)

    Динамика

    • Важные изменения объявляются через live-регион, существующий заранее
    • При смене маршрута в SPA обновляется title и переводится фокус
    • Состояния ARIA (aria-expanded, aria-pressed...) синхронны с интерфейсом

    Проверка

    • Линтер jsx-a11y без ошибок
    • axe (в тестах или расширении) без нарушений
    • Ключевые сценарии пройдены клавиатурой и хотя бы одним скринридером

    Источники и что читать дальше

    Стандарты и справочники

    Исследования и данные

    Практика и блоги

    Инструменты

    Доступность — не отдельная фича и не финальный аудит, а привычка, такая же, как адаптивная вёрстка. Начните с малого: подписи к полям, видимый фокус, контраст и правильные кнопки закрывают большую часть того, на чём спотыкаются пользователи. Остальное приходит с практикой.

    Серия «Доступный веб на практике»

    1. Доступность сайта: для кого она на самом деле и с чего начать
    2. Семантический HTML и альтернативный текст: фундамент доступного сайта
    3. Доступные формы: подписи, подсказки, ошибки и автозаполнение
    4. Клавиатура и фокус: как сделать сайт, которым можно пользоваться без мыши
    5. Контраст, анимация и размер кнопок: визуальная доступность сайта
    6. ARIA и динамический контент: когда атрибуты помогают, а когда вредят
    7. Доступность в React: id, фокус при смене маршрута и объявления
    8. Как тестировать доступность: автоматика, ручная проверка и чеклист — вы здесь

    Agama Labs — разработка сайтов и веб-приложений. Если хотите проверить доступность своего сайта, напишите нам: hello@agamalabs.com

    Контакты

    Давайте обсудим ваш проект

    Оставьте заявку, и мы свяжемся с вами в течение 2 часов для бесплатной консультации. Расскажите о вашей идее — поможем найти оптимальное решение.

    Время работы

    Пн–Пт: 08:00 – 17:00 (PST)
    Сб–Вс: Выходной

    Оставить заявку

    Заполните форму, и мы перезвоним вам

    Нажимая кнопку, вы соглашаетесь с политикой конфиденциальности

    Мы ценим вашу конфиденциальность

    Мы используем аналитические cookies, в том числе сторонних сервисов, чтобы понимать, как используется сайт, и улучшать его