user-event
Simulates the full sequence of real browser events so Testing Library tests behave the way an actual user does.
Repository Health
Technical Analysis
user-event is the companion library to @testing-library/dom (and by extension React Testing Library, Vue Testing Library, and the rest of the Testing Library family) for firing events the way a real user would trigger them, rather than the single low-level DOM event that fireEvent dispatches. Clicking a checkbox with user-event doesn’t just fire a click event — it walks through pointer-down, focus, pointer-up, and click, updating the element’s state along the way, the same as clicking it in a browser would.
The library is built around two layers: a stateful setup() session that tracks keyboard modifier and pointer button state across calls (so pressing {Shift>} in one keyboard() call stays held for the next), and a set of convenience methods (click, type, tab, hover, selectOptions, upload, clipboard.paste, and more) built on top of that shared state. Internally it models keyboard and pointer interaction as explicit System state machines fed by a small event-dispatch layer, so every convenience method ultimately resolves to the same primitive event sequence a browser would produce.
What You Get
- A stateful
userEvent.setup()session API that shares keyboard/pointer state across multiple interaction calls in a single test - High-level convenience methods —
click,dblClick,tripleClick,hover,unhover,tab— for common interactions - A
keyboard()API with a small DSL ({Shift>},{Enter},[KeyA]) for precise key-by-key and modifier-aware typing - A low-level
pointer()API for scripting multi-step pointer/touch/pen interaction sequences (press, move, release) - Clipboard integration (
copy,cut,paste) backed by a stubbed clipboard so paste-driven UI logic can be tested - Form-focused utilities:
type,clear,upload,selectOptions,deselectOptionsfor exercising inputs, file pickers, and<select>elements
Common Use Cases
- Typing into a form field character-by-character to trigger the same
onChange/onKeyDownhandlers a real keystroke would - Testing keyboard-only navigation flows (
tab()through focusable elements) for accessibility coverage - Simulating drag-style or multi-step pointer interactions (press-move-release) for custom UI widgets
- Verifying clipboard-driven features by scripting
copy/pasteagainst a stubbed clipboard - Uploading files to an
<input type="file">in tests without touching the real filesystem dialog
Under The Hood
Architecture
A setup() call produces a shared Instance object holding config, a System state machine, and the userEventApi method map; every convenience method is wrapped through a level-tracking async wrapper before it dispatches events via a dedicated event layer, so calls made against one session compose consistently. Keyboard and pointer state live as separate System sub-machines that convenience methods, the keyboard DSL, and the pointer API all read and mutate, which is what lets sequential calls on one instance behave like a continuous user session rather than isolated one-off actions.
Tech Stack
Written entirely in TypeScript and built with an esbuild-based pipeline (via the shared kcd-scripts toolchain), targeting CJS output. Tests run under Jest with a jsdom environment, configured through the same shared tooling. The package’s only runtime dependency is a peer dependency on @testing-library/dom — everything else in its dependency list is build or test tooling.
Code Quality
The test suite mirrors the source tree section-for-section (clipboard, convenience, document, event, keyboard, pointer, setup, system, utility), backed by shared test helpers for rendering fixtures and capturing dispatched events. Path aliases keep test imports pointed at source and helpers directly. Linting runs through a shared flat ESLint config augmented with project-specific custom rules, and CI runs a typecheck pass ahead of the test suite, indicating a strict, enforced quality bar.
API Design
The central ergonomic choice is offering both a one-off direct call (userEvent.click(el)) and a stateful session (userEvent.setup() then user.click(el)) from the same method surface, so simple tests stay terse while multi-step interactions can share keyboard/pointer state. A compact keyboard description syntax (holding modifiers, naming specific physical keys) lets a single string argument express what would otherwise require several imperative press/release calls.
Used by 116 apps in this directory
Colanode
Collaboration · Knowledge Management · Team Chat
Local-first, self-hosted workspace that combines real-time chat, Notion-style pages, and structured databases — all synced via CRDTs so you work offline without losing a keystroke.
Continue
AI Code Assistants · AI Development · Automation
Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.
Convex Backend
Databases · Developer Tools
Open-source reactive database that lets developers build live-updating apps with pure TypeScript, strong consistency, and real-time subscriptions—no separate API layer required.
Cosmos-Server
Authentication · Security
All-in-one self-hosted home server with SmartShield anti-DDoS, Nebula mesh VPN, automatic HTTPS, and a 250-app marketplace — all secured behind a unified auth layer.
CourseLit
Blogging · Ecommerce
Open-source, self-hosted LMS for selling online courses, digital downloads, and building communities on your own branded website.
DenchClaw
AI Agents · CRM
An AI-native CRM you self-host on your own machine, built on the OpenClaw agent framework, with a DuckDB backend and pre-built agent skills for managing contacts, deals, reports, and 500+ outreach integrations from natural-language chat.
Dify
AI Development · Design Tools · Developer Tools
Visual LLM workflow platform with RAG pipelines, agent capabilities, and model management for building production AI applications.
Docs
CMS · File Storage
Open-source collaborative knowledge platform with real-time editing, AI writing tools, and full self-hosting control — built by the French and German governments.
e2a
AI Agents · Automation
Give your AI agents a real, authenticated email address — with SPF/DKIM-verified inbound, HMAC-signed delivery, WebSocket fan-out, and human-in-the-loop approval built in.