Библиотека ally.js предназначена для управления доступностью элементов на веб-странице, в первую очередь с точки зрения фокуса и клавиатурной навигации. Она предоставляет инструменты для проверки доступности, перемещения фокуса и работы с интерактивными элементами.
Главным объектом взаимодействия является ally. Он позволяет:
Пример базового поиска всех элементов, которые могут быть сфокусированы:
const focusableElements = ally.query.focusable({ context: document.body });
Аргумент context позволяет ограничить область поиска
определённым контейнером. Функция возвращает массив DOM-элементов,
которые можно использовать для управления фокусом.
Ally.js позволяет определить, может ли конкретный элемент получить фокус. Это важно для юнит-тестов, где нужно убедиться, что элементы интерфейса корректно участвуют в навигации клавиатурой.
const button = document.querySelector('#submit');
const isFocusable = ally.query.is.focusable(button);
console.log(isFocusable); // true или false
Метод ally.query.is.focusable учитывает:
display: none,
visibility: hidden).tabindex.Для тестирования интерактивных компонентов это ключевой инструмент, позволяющий автоматически проверять состояние фокуса.
Для перемещения фокуса между элементами используется функция
ally.focus(). Она обеспечивает корректное выделение
элемента с учётом всех правил доступности.
const input = document.querySelector('#email');
ally.focus(input);
Важные параметры функции:
context — контейнер, в котором производится поиск.ignore — селекторы элементов, которые следует
пропустить.strategy — способ выбора элемента (по умолчанию
first, можно использовать last,
next, previous).Пример установки фокуса на первый доступный элемент формы:
ally.focus.first({ context: document.querySelector('form') });
Ally.js предоставляет возможности для навигации фокуса в модальных окнах, всплывающих меню и других динамических интерфейсах.
const modal = document.querySelector('#modal');
ally.focus.trap(modal, {
ignoreClicks: true
});
ally.focus.trap позволяет:
Это критично для юнит-тестов, которые проверяют сценарии взаимодействия с пользователем, включая открытие и закрытие модальных компонентов.
Для автоматических тестов используется комбинация ally.js и тестовых библиотек (например, Jest или Mocha). Основные сценарии тестирования фокуса:
tabindex).Пример теста с Jest:
test('Кнопка submit доступна для фокуса', () => {
document.body.innerHTML = `<button id="submit">Отправить</button>`;
const button = document.querySelector('#submit');
expect(ally.query.is.focusable(button)).toBe(true);
});
Пример теста с focus trap:
test('Фокус остаётся внутри модального окна', () => {
document.body.innerHTML = `
<div id="modal" tabindex="-1">
<button id="ok">OK</button>
<button id="cancel">Cancel</button>
</div>
`;
const modal = document.querySelector('#modal');
ally.focus.trap(modal);
const okButton = document.querySelector('#ok');
ally.focus(okButton);
expect(document.activeElement).toBe(okButton);
});
Ally.js учитывает атрибут tabindex для определения
последовательности фокусировки.
tabindex="0" — элемент включается в естественный
порядок табуляции.tabindex="-1" — элемент можно сфокусировать программно,
но он исключён из табуляции.tabindex="positive number" — приоритетный порядок
фокуса.Пример проверки правильного порядка:
const elements = ally.query.focusable({ context: document.body });
const order = elements.map(el => el.id);
console.log(order); // ['firstInput', 'secondInput', 'submitButton']
Юнит-тест может проверять, что элементы в DOM соответствуют ожидаемому порядку.
Ally.js автоматически исключает из фокуса:
display: none или
visibility: hidden.<input disabled>,
<button disabled>.href для ссылок.Это позволяет в тестах фокусироваться только на реально доступных пользователю элементах.
const hiddenButton = document.createElement('button');
hiddenButton.style.display = 'none';
document.body.appendChild(hiddenButton);
expect(ally.query.is.focusable(hiddenButton)).toBe(false);
Для компонентов, которые динамически загружаются (например, через AJAX), ally.js поддерживает асинхронные сценарии:
setTimeout(() => {
const newInput = document.createElement('input');
document.body.appendChild(newInput);
ally.focus(newInput);
}, 100);
Тесты должны учитывать задержку, используя асинхронные функции или
await для правильной проверки состояния фокуса.
tabindex.Такой подход обеспечивает надёжное тестирование интерактивных компонентов интерфейса с точки зрения доступности.