User Interactions
Simulate realistic clicks, typing, and form submission with userEvent.
userEvent Setup
@testing-library/user-event v14+ requires userEvent.setup() per test for isolated pointer/keyboard state. Async API—await each interaction.
userEvent fires full event sequence closer to real browser than fireEvent alone.
import userEvent from "@testing-library/user-event";
test("submits form", async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={jest.fn()} />);
await user.type(screen.getByLabelText(/email/i), "ada@example.com");
await user.click(screen.getByRole("button", { name: /sign in/i }));
});Click and Keyboard
user.click, dblClick, hover, tab, keyboard shortcuts. clear empties input before type. selectOptions for native select elements.
For keyboard-only flows test tab order and Enter activation on buttons.
await user.click(screen.getByRole("checkbox", { name: /remember/i }));
await user.keyboard("{Tab}{Enter}");fireEvent When Appropriate
fireEvent dispatches single synthetic event—lower level. Use when userEvent does not support edge case or testing error boundary on specific event.
Prefer userEvent for integration confidence; fireEvent for isolated unit triggering one event.
- userEvent.type handles focus and keydown/keyup sequence
- upload file with user.upload or fireEvent on input
- pointer events for custom sliders may need low-level sequence
import { fireEvent } from "@testing-library/react";
fireEvent.scroll(window, { target: { scrollY: 500 } });Form Submission
Fill fields with user.type or user.selectOptions, submit with click submit button or user.keyboard("{Enter}") in field. Assert onSubmit called with expected payload or success UI.
Validation errors: assert error messages appear without submit when client validation blocks.
const handleSubmit = jest.fn();
render(<ContactForm onSubmit={handleSubmit} />);
await user.type(screen.getByLabelText(/message/i), "Hello");
await user.click(screen.getByRole("button", { name: /send/i }));
expect(handleSubmit).toHaveBeenCalledWith({ message: "Hello" });Pointer and Drag
userEvent pointer API supports press, move, release for drag-drop libraries. Coordinate with library docs—some DnD needs HTML5 DnD events fireEvent supplies.
Avoid testing CSS hover-only UI as sole path—ensure keyboard accessible alternative exists and test that too.
- Use { delay: null } in setup for faster typing in large forms
- Disabled controls should fail user.click—assert disabled state first
- Double-check async await on every userEvent call