Simple and complete DOM testing utilities that encourage good testing practices.
—
Complete reference for all query methods. Every query type supports three variants (get/query/find) with plural forms (getAll/queryAll/findAll).
// Single element queries
function getBy*<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: Options
): T; // Throws if 0 or 2+ matches
function queryBy*<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: Options
): T | null; // Returns null if not found
function findBy*<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: Options,
waitOptions?: waitForOptions
): Promise<T>; // Waits up to 1000ms
// Plural element queries
function getAllBy*<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: Options
): T[]; // Throws if 0 matches found
function queryAllBy*<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: Options
): T[]; // Returns empty array if none found
function findAllBy*<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: Options,
waitOptions?: waitForOptions
): Promise<T[]>; // Waits up to 1000msQuery by ARIA role - most accessible method.
function getByRole<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
role: ByRoleMatcher,
options?: ByRoleOptions
): T;
interface ByRoleOptions {
// Filter by accessible name (label, aria-label, aria-labelledby)
name?: Matcher;
// Filter by accessible description (aria-describedby)
description?: Matcher;
// Hidden elements
hidden?: boolean; // Default: false
// ARIA states
selected?: boolean;
checked?: boolean;
pressed?: boolean;
expanded?: boolean;
busy?: boolean;
current?: boolean | string;
// ARIA properties
level?: number; // For headings
value?: {now?: number; min?: number; max?: number; text?: Matcher};
// Other
queryFallbacks?: boolean; // Include elements without explicit role
suggest?: boolean; // Include query suggestions in errors
}
type ByRoleMatcher = ARIARole | string;Examples:
// Basic
getByRole(container, 'button');
getByRole(container, 'button', {name: /submit/i});
// States
getByRole(container, 'checkbox', {checked: true});
getByRole(container, 'tab', {selected: true});
// Properties
getByRole(container, 'heading', {level: 1});
getByRole(container, 'progressbar', {value: {now: 50, min: 0, max: 100}});
// Hidden elements
getByRole(container, 'alert', {hidden: true});Query form elements by associated label - recommended for forms.
function getByLabelText<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: SelectorMatcherOptions
): T;
interface SelectorMatcherOptions extends MatcherOptions {
selector?: string; // Narrow by selector (e.g., 'input[type="email"]')
ignore?: boolean | string; // CSS selectors to ignore
}Examples:
getByLabelText(container, 'Email');
getByLabelText(container, 'Email', {selector: 'input[type="email"]'});
// Matches <label>Email</label><input id="email" />
// And <input aria-label="Email" />Query form elements by placeholder attribute.
function getByPlaceholderText<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: MatcherOptions
): T;Examples:
getByPlaceholderText(container, 'Search...');
getByPlaceholderText(container, /enter.*email/i);Query by visible text content - good for non-interactive elements.
function getByText<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: SelectorMatcherOptions
): T;Examples:
getByText(container, 'Welcome');
getByText(container, /error/i);
getByText(container, (content, el) => content.startsWith('Total:'));
// With selector
getByText(container, 'Submit', {selector: 'button'});
// Ignore elements
getByText(container, 'Content', {ignore: 'script, style'});Query form elements by current value.
function getByDisplayValue<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
value: Matcher,
options?: MatcherOptions
): T;Examples:
getByDisplayValue(container, 'Hello World'); // Finds input/textarea with this value
getByDisplayValue(container, 'Option 1'); // Finds select with this option selectedQuery images and other elements by alt attribute.
function getByAltText<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: MatcherOptions
): T;Examples:
getByAltText(container, 'Company logo');
getByAltText(container, /user avatar/i);Query by title attribute.
function getByTitle<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
text: Matcher,
options?: MatcherOptions
): T;Examples:
getByTitle(container, 'More information');
getByTitle(container, /delete item/i);Query by test ID attribute - only use when no better query is available.
function getByTestId<T extends HTMLElement = HTMLElement>(
container: HTMLElement,
id: Matcher,
options?: MatcherOptions
): T;
// Configure custom test ID attribute
configure({testIdAttribute: 'data-test-id'});Examples:
getByTestId(container, 'submit-button');
// With custom attribute
configure({testIdAttribute: 'data-cy'});
getByTestId(container, 'submit-button'); // Now looks for data-cyCommon options for matcher-based queries:
interface MatcherOptions {
exact?: boolean; // Match exactly (default: false)
trim?: boolean; // Trim whitespace (default: true)
collapseWhitespace?: boolean; // Collapse whitespace (default: true)
normalizer?: (text: string) => string; // Custom text normalizer
suggest?: boolean; // Include query suggestions in errors
}Examples:
// Exact match
getByText(container, 'Submit', {exact: true});
// Custom normalizer
getByText(container, 'submit', {normalizer: str => str.toLowerCase()});
// Disable whitespace normalization
getByText(container, 'Text with multiple spaces', {
collapseWhitespace: false
});type Matcher = string | RegExp | number | MatcherFunction;
type MatcherFunction = (content: string, element: Element | null) => boolean;Usage:
// String
getByText(container, 'Text');
// Regex
getByText(container, /text/i);
// Number (converted to string)
getByText(container, 42);
// Function
getByText(container, (content, el) => {
return content.includes('Total:') && el.tagName === 'SPAN';
});// Bad - throws error
getByText(container, 'Should not exist');
// Good - returns null if not found
expect(queryByText(container, 'Should not exist')).not.toBeInTheDocument();await waitFor(() => {
expect(screen.getAllByRole('listitem')).toHaveLength(5);
});const form = screen.getByRole('form');
const email = within(form).getByLabelText('Email');Install with Tessl CLI
npx tessl i tessl/npm-testing-library--dom@10.4.2