Browser runner for Vitest enabling tests to run in actual browser environments with real DOM APIs and browser-specific features
—
Comprehensive user event simulation supporting keyboard input, mouse interactions, form manipulation, and file uploads with provider-specific implementations for realistic browser testing.
Simulate mouse events including clicks, hovers, and drag operations.
/**
* Click on an element. Uses provider's API under the hood and supports all its options.
* @param element - Target element or locator
* @param options - Provider-specific click options
*/
click(element: Element | Locator, options?: UserEventClickOptions): Promise<void>;
/**
* Triggers a double click event on an element
* @param element - Target element or locator
* @param options - Provider-specific double click options
*/
dblClick(element: Element | Locator, options?: UserEventDoubleClickOptions): Promise<void>;
/**
* Triggers a triple click event on an element
* @param element - Target element or locator
* @param options - Provider-specific triple click options
*/
tripleClick(element: Element | Locator, options?: UserEventTripleClickOptions): Promise<void>;
/**
* Hovers over an element
* @param element - Target element or locator
* @param options - Provider-specific hover options
*/
hover(element: Element | Locator, options?: UserEventHoverOptions): Promise<void>;
/**
* Moves cursor position to the body element
* @param element - Element to move away from
* @param options - Provider-specific hover options
*/
unhover(element: Element | Locator, options?: UserEventHoverOptions): Promise<void>;
/**
* Drags a source element on top of the target element (not supported by preview provider)
* @param source - Source element or locator
* @param target - Target element or locator
* @param options - Provider-specific drag options
*/
dragAndDrop(source: Element | Locator, target: Element | Locator, options?: UserEventDragAndDropOptions): Promise<void>;Usage Examples:
import { userEvent, page } from "@vitest/browser/context";
// Basic mouse interactions
await userEvent.click(page.getByRole("button", { name: "Submit" }));
await userEvent.dblClick(page.getByText("Double click me"));
await userEvent.tripleClick(page.getByText("Select all text"));
// Hover interactions
await userEvent.hover(page.getByRole("menu"));
await userEvent.unhover(page.getByRole("menu"));
// Drag and drop
const sourceItem = page.getByTestId("drag-source");
const targetArea = page.getByTestId("drop-target");
await userEvent.dragAndDrop(sourceItem, targetArea);
// Provider-specific options (example with Playwright)
await userEvent.click(page.getByRole("button"), {
position: { x: 10, y: 10 }, // Click at specific position
button: "right" // Right click
});Handle keyboard events including typing, key combinations, and navigation.
/**
* Type text on the keyboard. If any input is focused, it will receive the text,
* otherwise it will be typed on the document. Supports user-event keyboard syntax.
* @param text - Text to type (supports {Shift}, {Ctrl}, etc. syntax)
*/
keyboard(text: string): Promise<void>;
/**
* Types text into an element. Supports user-event keyboard syntax.
* This method can be significantly slower than fill(), so use only when necessary.
* @param element - Target element or locator
* @param text - Text to type (supports keyboard syntax)
* @param options - Typing options
*/
type(element: Element | Locator, text: string, options?: UserEventTypeOptions): Promise<void>;
/**
* Sends a Tab key event
* @param options - Tab options
*/
tab(options?: UserEventTabOptions): Promise<void>;Usage Examples:
import { userEvent, page } from "@vitest/browser/context";
// Basic keyboard input
await userEvent.keyboard("Hello World");
// Keyboard shortcuts
await userEvent.keyboard("{Ctrl}a"); // Select all
await userEvent.keyboard("{Ctrl}c"); // Copy
await userEvent.keyboard("{Ctrl}v"); // Paste
await userEvent.keyboard("{Shift}{Tab}"); // Shift+Tab
// Complex key combinations
await userEvent.keyboard("{Ctrl}{Shift}i"); // Open dev tools
await userEvent.keyboard("{Alt}f4"); // Alt+F4
// Type into specific elements
await userEvent.type(page.getByLabelText("Username"), "johndoe");
await userEvent.type(page.getByLabelText("Password"), "{Ctrl}a{Delete}newpassword");
// Tab navigation
await userEvent.tab(); // Tab forward
await userEvent.tab({ shift: true }); // Tab backward
// Escape sequences for literal characters
await userEvent.keyboard("{{"); // Types a literal {
await userEvent.keyboard("[["); // Types a literal [Handle form inputs, selections, and file uploads.
/**
* Fills an input element with text. Removes existing text before typing.
* Faster than type() but doesn't support keyboard syntax.
* @param element - Target input element or locator
* @param text - Text to fill (literal text only)
* @param options - Fill options
*/
fill(element: Element | Locator, text: string, options?: UserEventFillOptions): Promise<void>;
/**
* Removes all text from an element
* @param element - Target element or locator
* @param options - Clear options
*/
clear(element: Element | Locator, options?: UserEventClearOptions): Promise<void>;
/**
* Choose one or more values from a select element
* @param element - Target select element
* @param values - Values to select (strings, elements, or locators)
* @param options - Selection options
*/
selectOptions(
element: Element,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
/**
* Change a file input element to have the specified files
* @param element - Target file input element or locator
* @param files - Files to upload (File objects or file paths)
* @param options - Upload options
*/
upload(element: Element | Locator, files: File | File[] | string | string[], options?: UserEventUploadOptions): Promise<void>;Usage Examples:
import { userEvent, page } from "@vitest/browser/context";
// Form filling
await userEvent.fill(page.getByLabelText("Email"), "user@example.com");
await userEvent.fill(page.getByLabelText("Password"), "secretpassword");
// Clear existing content
await userEvent.clear(page.getByLabelText("Search"));
// Select dropdown options
const countrySelect = page.getByLabelText("Country");
await userEvent.selectOptions(countrySelect, "United States");
// Multiple selections
await userEvent.selectOptions(countrySelect, ["US", "CA", "MX"]);
// Select by option elements
await userEvent.selectOptions(countrySelect, [
page.getByRole("option", { name: "United States" }),
page.getByRole("option", { name: "Canada" })
]);
// File uploads
const fileInput = page.getByLabelText("Upload file");
// Upload with File objects
await userEvent.upload(fileInput, [
new File(["content"], "test.txt", { type: "text/plain" }),
new File(["image data"], "image.png", { type: "image/png" })
]);
// Upload with file paths (server-side files)
await userEvent.upload(fileInput, ["./fixtures/test-file.pdf"]);Handle copy, cut, and paste operations.
/**
* Copies the selected content
*/
copy(): Promise<void>;
/**
* Cuts the selected content
*/
cut(): Promise<void>;
/**
* Pastes the copied or cut content
*/
paste(): Promise<void>;Usage Examples:
import { userEvent, page } from "@vitest/browser/context";
// Select and copy text
const textElement = page.getByText("Important text to copy");
await userEvent.tripleClick(textElement); // Select all text
await userEvent.copy();
// Cut from input field
const inputField = page.getByLabelText("Source text");
await userEvent.keyboard("{Ctrl}a"); // Select all
await userEvent.cut();
// Paste into another field
const targetField = page.getByLabelText("Destination");
await userEvent.click(targetField);
await userEvent.paste();
// Copy-paste workflow
await userEvent.keyboard("{Ctrl}a"); // Select all
await userEvent.copy(); // Copy
await userEvent.click(page.getByLabelText("Backup field"));
await userEvent.paste(); // PasteCreate and manage separate user event instances with independent state.
/**
* Creates a new user event instance with separate keyboard state
* @returns New UserEvent instance
*/
setup(): UserEvent;
/**
* Cleans up the user event instance, releasing any resources or state
*/
cleanup(): Promise<void>;Usage Examples:
import { userEvent } from "@vitest/browser/context";
// Create separate instance for complex interactions
const userEvent2 = userEvent.setup();
// Each instance maintains its own keyboard state
await userEvent.keyboard("{Shift}"); // Hold shift in default instance
await userEvent2.keyboard("text"); // Type in second instance (no shift)
// Clean up when done
await userEvent2.cleanup();
// Useful for parallel operations or state isolation
test("multiple user sessions", async () => {
const user1 = userEvent.setup();
const user2 = userEvent.setup();
// Simulate two users typing simultaneously
await Promise.all([
user1.type(page.getByLabelText("User 1 input"), "Hello"),
user2.type(page.getByLabelText("User 2 input"), "World")
]);
await user1.cleanup();
await user2.cleanup();
});Complex interaction patterns and provider-specific features.
Drag and Drop with Custom Positions:
// Drag with specific coordinates (WebdriverIO)
await userEvent.dragAndDrop(sourceElement, targetElement, {
sourceX: 10,
sourceY: 10,
targetX: 50,
targetY: 50
});File Upload with Custom File Properties:
// Create files with specific properties
const csvFile = new File(
["name,age\nJohn,30\nJane,25"],
"users.csv",
{ type: "text/csv", lastModified: Date.now() }
);
await userEvent.upload(page.getByLabelText("Import CSV"), csvFile);Complex Form Interactions:
// Multi-step form interaction
const form = page.getByRole("form");
await userEvent.fill(form.getByLabelText("First Name"), "John");
await userEvent.fill(form.getByLabelText("Last Name"), "Doe");
await userEvent.selectOptions(form.getByLabelText("Country"), "US");
await userEvent.click(form.getByLabelText("Agree to terms"));
await userEvent.upload(form.getByLabelText("Profile Picture"), profileImage);
await userEvent.click(form.getByRole("button", { name: "Submit" }));Option interfaces for user interaction methods:
interface UserEventClickOptions {
// Provider-specific options (e.g., Playwright click options)
}
interface UserEventDoubleClickOptions {
// Provider-specific options
}
interface UserEventTripleClickOptions {
// Provider-specific options
}
interface UserEventFillOptions {
// Provider-specific options
}
interface UserEventClearOptions {
// Provider-specific options
}
interface UserEventHoverOptions {
// Provider-specific options
}
interface UserEventSelectOptions {
// Provider-specific options
}
interface UserEventUploadOptions {
// Provider-specific options
}
interface UserEventDragAndDropOptions {
// Provider-specific options
}
interface UserEventTabOptions {
/** Whether to hold Shift while pressing Tab */
shift?: boolean;
}
interface UserEventTypeOptions {
/** Whether to skip the initial click on the element */
skipClick?: boolean;
/** Whether to skip automatic closing of dialogs */
skipAutoClose?: boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-vitest--browser