CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-testing-library--dom

Simple and complete DOM testing utilities that encourage good testing practices.

Pending
Overview
Eval results
Files

queries.mddocs/

DOM Queries

Complete reference for all query methods. Every query type supports three variants (get/query/find) with plural forms (getAll/queryAll/findAll).

Query Variants

// 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 1000ms

Query by Role (Recommended)

Query 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 by Label Text

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 by Placeholder Text

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 Text

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 by Display Value

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 selected

Query by Alt Text

Query 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

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 (Last Resort)

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-cy

Matcher Options

Common 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
});

Matcher Types

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';
});

Common Patterns

Asserting non-existence

// Bad - throws error
getByText(container, 'Should not exist');

// Good - returns null if not found
expect(queryByText(container, 'Should not exist')).not.toBeInTheDocument();

Waiting for multiple elements

await waitFor(() => {
  expect(screen.getAllByRole('listitem')).toHaveLength(5);
});

Narrow by container

const form = screen.getByRole('form');
const email = within(form).getByLabelText('Email');

Install with Tessl CLI

npx tessl i tessl/npm-testing-library--dom

docs

async.md

config.md

debugging.md

events.md

index.md

queries.md

query-helpers.md

role-utilities.md

screen.md

within.md

tile.json