14. User Events

userEvent vs fireEvent
Заголовок раздела «userEvent vs fireEvent»// fireEvent — низкоуровневый (прямая эмуляция событий)import { fireEvent } from '@testing-library/react';fireEvent.click(button);fireEvent.change(input, { target: { value: 'text' } });
// userEvent — высокоуровневый (симулирует реальные действия пользователя)import userEvent from '@testing-library/user-event';const user = userEvent.setup();await user.click(button); // hover → focus → click → blurawait user.type(input, 'text'); // каждый символ отдельно
// Используй userEvent — он реалистичнее!Настройка userEvent
Заголовок раздела «Настройка userEvent»import userEvent from '@testing-library/user-event';
describe('Form', () => { // Лучший способ: setup() один раз const user = userEvent.setup();
test('submits form', async () => { render(<LoginForm onSubmit={mockSubmit} />); await user.click(screen.getByRole('button', { name: /submit/i })); expect(mockSubmit).toHaveBeenCalled(); });});// Обычный кликawait user.click(screen.getByRole('button'));
// Двойной кликawait user.dblClick(screen.getByText('Item'));
// Правый кликawait user.pointer({ keys: '[MouseRight]', target: element });
// Клик с модификаторомawait user.keyboard('{Control>}');await user.click(screen.getByRole('checkbox'));await user.keyboard('{/Control}');
// Клик по координатам (редко нужно)await user.pointer({ coords: { x: 100, y: 200 } });Ввод текста
Заголовок раздела «Ввод текста»// type: как пользователь — каждый символ отдельноawait user.type(input, 'Hello World');expect(input).toHaveValue('Hello World');
// type с очисткойawait user.clear(input);await user.type(input, 'New text');
// Специальные клавишиawait user.type(input, 'Hello{Enter}'); // нажать Enterawait user.type(input, '{Backspace}'); // удалить символawait user.type(input, '{selectall}Delete'); // выделить всё и удалить
// Полный список: {Enter} {Tab} {Escape} {Backspace} {Delete}// {ArrowLeft} {ArrowRight} {ArrowUp} {ArrowDown}// {Home} {End} {PageUp} {PageDown}// {Control} {Shift} {Alt} {Meta}
// keyboard: прямой ввод клавишawait user.keyboard('Hello');await user.keyboard('{Enter}');
// paste: вставить как из буфераawait user.paste('pasted content');Чекбоксы и радио
Заголовок раздела «Чекбоксы и радио»render( <form> <input type="checkbox" id="agree" /> <label htmlFor="agree">I agree</label>
<input type="radio" name="plan" value="free" id="free" /> <label htmlFor="free">Free</label>
<input type="radio" name="plan" value="pro" id="pro" /> <label htmlFor="pro">Pro</label> </form>);
// Checkboxconst checkbox = screen.getByRole('checkbox', { name: /agree/i });expect(checkbox).not.toBeChecked();await user.click(checkbox);expect(checkbox).toBeChecked();await user.click(checkbox);expect(checkbox).not.toBeChecked();
// Radioawait user.click(screen.getByLabelText('Free'));expect(screen.getByLabelText('Free')).toBeChecked();expect(screen.getByLabelText('Pro')).not.toBeChecked();
await user.click(screen.getByLabelText('Pro'));expect(screen.getByLabelText('Pro')).toBeChecked();Select (выпадающий список)
Заголовок раздела «Select (выпадающий список)»<select name="country"> <option value="">Choose...</option> <option value="ru">Russia</option> <option value="es">Spain</option></select>const select = screen.getByRole('combobox');await user.selectOptions(select, 'ru');expect(select).toHaveValue('ru');
await user.selectOptions(select, ['ru', 'es']); // мультиселектDrag and Drop
Заголовок раздела «Drag and Drop»const source = screen.getByTestId('drag-source');const target = screen.getByTestId('drop-target');
await user.pointer([ { keys: '[MouseLeft>]', target: source }, { target }, { keys: '[/MouseLeft]' },]);Tab навигация
Заголовок раздела «Tab навигация»// Переключение между элементами формыrender(<LoginForm />);
await user.tab(); // перейти к первому focusable элементуexpect(screen.getByLabelText('Email')).toHaveFocus();
await user.tab();expect(screen.getByLabelText('Password')).toHaveFocus();
await user.tab();expect(screen.getByRole('button', { name: /submit/i })).toHaveFocus();
await user.keyboard('{Enter}'); // нажать focused кнопкуПрактические задания
Заголовок раздела «Практические задания»- Протестируй форму регистрации: ввод данных и отправка
- Протестируй компонент Accordion: открытие/закрытие по клику
- Протестируй навигацию по табам с клавиатуры
- userEvent реалистичнее fireEvent — предпочитай его
- user.setup() → await user.action() — современный способ
- type, click, keyboard, selectOptions — основные методы
- Специальные клавиши в фигурных скобках:
{Enter},{Backspace}