Обидва викликають події в тесті, але на різному рівні.
fireEvent відправляє одну конкретну подію DOM:
fireEvent.change(input, { target: { value: 'Оля' } });
fireEvent.click(button);
change одразу встановлює значення - без фокусу, без натискань клавіш, без подій keydown/input/keyup для кожної літери.
userEvent імітує дії користувача - послідовність подій, яку згенерував би браузер:
import userEvent from '@testing-library/user-event';
test('пошук', async () => {
const user = userEvent.setup();
render(<Search />);
await user.type(screen.getByRole('searchbox'), 'laravel');
await user.keyboard('{Enter}');
await user.click(screen.getByRole('button', { name: 'Очистити' }));
});
user.type для кожної літери викликає keydown, keypress, input, keyup, переводить фокус на поле кліком; user.click - pointerdown, mousedown, focus, pointerup, mouseup, click.
Чому userEvent кращий за замовчуванням:
- ловить реальні помилки: не дасть клікнути кнопку з
disabledчиpointer-events: none, не введе текст у поле лише для читання.fireEvent.clickспрацює на заблокованій кнопці - тест пройде, а користувач натиснути не зможе; - обробники, що реагують на
keydownчиfocus, отримують свої події; - вбудовані дії:
user.selectOptions,user.upload,user.tab()(перевірка порядку фокусу),user.hover,user.clear,user.paste.
Правила роботи з userEvent 14:
- створювати екземпляр через
userEvent.setup()на початку тесту (доrender); - усі методи асинхронні - обов'язково
await; - з фальшивими таймерами -
userEvent.setup({ advanceTimers: vi.advanceTimersByTime }), інакше тест «зависне» на внутрішніх затримках.
Коли fireEvent доречний:
- подія, яку
userEventне підтримує (scroll,resize, власні події, події медіа); - точне відтворення однієї події для перевірки обробника.
Обидва вже обгорнуті в act, тож оновлення стану після події застосовуються до наступної перевірки.