При тестировании интерфейсов на React часто требуется проверять поведение компонентов при взаимодействии с клавиатурой. Это особенно важно для форм, модальных окон, кастомных селекторов и любых элементов, где пользователь может использовать не только мышь, но и клавиши. React Testing Library предоставляет инструменты для эмуляции таких событий, включая работу со специальными клавишами.
fireEvent и
клавиатурные событияОсновной метод для имитации событий клавиатуры —
fireEvent. С его помощью можно отправлять события
keydown, keypress и keyup. Для
специальных клавиш важно использовать правильные свойства события:
key — строковое представление клавиши, например
"Enter", "Escape",
"ArrowDown".code — физическая клавиша на клавиатуре, например
"Enter", "Escape",
"ArrowDown".keyCode — числовое значение клавиши (устаревшее, но
иногда используется в старых обработчиках).Пример отправки события нажатия Enter:
import { render, fireEvent } from '@testing-library/react';
import MyInput from './MyInput';
test('нажатие Enter вызывает submit', () => {
const handleSubmit = jest.fn();
const { getByRole } = render(<MyInput onSub mit={handleSubmit} />);
const input = getByRole('textbox');
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', keyCode: 13 });
expect(handleSubmit).toHaveBeenCalledTimes(1);
});
Здесь ключевой момент — использование именно keyDown для
имитации нажатия. В большинстве случаев обработчики форм реагируют
именно на keydown.
Клавиши-модификаторы и навигации требуют особого внимания.
Модификаторы: Shift,
Control, Alt, Meta
fireEvent.keyDown(input, { key: 'A', code: 'KeyA', shiftKey: true });
shiftKey, ctrlKey, altKey,
metaKey — булевы значения, указывающие, удерживается ли
клавиша-модификатор.Навигационные клавиши: ArrowUp,
ArrowDown, ArrowLeft, ArrowRight,
Tab, Escape
fireEvent.keyDown(menuItem, { key: 'ArrowDown', code: 'ArrowDown' });
fireEvent.keyDown(menuItem, { key: 'Escape', code: 'Escape' });
Эти события полезны при тестировании выпадающих списков, меню и кастомных каруселей.
userEvent
для более реалистичной имитацииReact Testing Library рекомендует использовать библиотеку
@testing-library/user-event для более реалистичного
поведения. В отличие от fireEvent, userEvent
учитывает последовательность событий (keydown →
keypress → keyup) и фокус элемента.
Пример имитации нажатия Enter:
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyInput from './MyInput';
test('Enter вызывает submit с userEvent', async () => {
const handleSubmit = jest.fn();
const { getByRole } = render(<MyInput onSub mit={handleSubmit} />);
const input = getByRole('textbox');
await userEvent.type(input, 'Тест{Enter}');
expect(handleSubmit).toHaveBeenCalledTimes(1);
});
Здесь {Enter} — специальная запись для клавиш в
userEvent.type. Аналогично можно использовать
{Tab}, {Escape}, {ArrowDown} и
другие.
Особенность userEvent — автоматически ставит фокус на
элемент, что упрощает тестирование клавиатурной навигации.
Иногда поведение компонента зависит от сочетаний клавиш, например
Ctrl + S для сохранения:
fireEvent.keyDown(input, { key: 's', code: 'KeyS', ctrlKey: true });
Или с использованием userEvent:
await userEvent.keyboard('{Control>}{s}{/Control}');
{Control>} — удержание клавиши Control{s} — нажатие клавиши S{/Control} — отпускание ControlТакой синтаксис позволяет эмулировать сложные комбинации без
необходимости вручную выставлять флаги ctrlKey,
shiftKey и т. д.
Навигация с клавиатуры часто связана с перемещением фокуса. В тестах
можно проверять, какой элемент активен после нажатия
Tab:
import { screen } from '@testing-library/react';
await userEvent.tab(); // перемещает фокус на следующий элемент
expect(screen.getByRole('button')).toHaveFocus();
await userEvent.tab({ shift: true }); // перемещает фокус назад
expect(screen.getByRole('textbox')).toHaveFocus();
userEvent.tab() учитывает порядок табуляции, что делает
тестирование более приближенным к реальному поведению пользователя.
keyCode может различаться в старых
браузерах.code всегда соответствует физической клавише и удобен
для эмуляции одинаковых комбинаций.event.key, а не только keyCode.userEvent там, где важно поведение
фокуса.keyCode, опираясь
на key и code.Такой подход обеспечивает стабильность тестов и их соответствие реальному поведению пользователей.