npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mui-harness

v1.1.1

Published

Material UI test harness library built on dom-harness

Readme

mui-harness

npm version npm downloads TypeScript Bundle Size

A collection of test harnesses for Material UI components, built on top of dom-harness. Each harness wraps a MUI component and exposes a clean API for querying rendered state and simulating user interactions — no CSS class selectors scattered across your tests.

Why test harnesses?

You build your UI out of <Button>, <TextField>, and <Dialog> — your tests should work at the same level of abstraction.

Same abstraction as your UI. A harness lets you interact with a ButtonHarness, not a DOM node that happens to have a certain class. Tests read the way you think about the component.

Tests survive implementation changes. A component's internal markup, class names, and DOM structure are implementation details. When MUI changes them in a minor release (and it does), tests that reach into the DOM break. Harnesses absorb that change in one place.

Composition matches your mental model. A LoginFormHarness contains a TextFieldHarness and a ButtonHarness, just like the component tree. Tests read the way you think about the UI, not the way a browser sees it.

See the dom-harness README for deeper background on the harness pattern.

Examples

The examples/login-page directory contains a complete, runnable example — a login page built with MUI components and tested entirely through harnesses. Look at it to see:

  • Harness composition in practice. A LoginPageHarness contains an AuthPanelHarness, which contains LoginFormHarness and RegistrationFormHarness. Each layer composes MUI harnesses (TextFieldHarness, ButtonHarness, etc.) to expose a domain-specific API. This is the pattern you'll use in your own apps.
  • Tests that read like requirements. The test files show how harnesses let you write assertions at the level of "fill in email, click submit, check for error" rather than "query a DOM node by class name."
  • How to structure harnesses alongside components. Each component has a co-located harness file (LoginForm.tsxLoginFormHarness.tsLoginForm.test.tsx), showing where harnesses fit in a typical project layout.

Documentation

Full API reference and best practices are included in this package:

Installation

npm install mui-harness dom-harness

Peer dependencies

| Package | Version | |---|---| | dom-harness | * | | @mui/material | ^6.0.0 | | @testing-library/react | >=16.0.0 | | @testing-library/user-event | >=14.0.0 | | react | >=19.0.0 |

Quick start

import { render } from '@testing-library/react';
import { ButtonHarness, AlertHarness } from 'mui-harness';

it('submits the form and shows a success alert', async () => {
  render(<MyForm />);

  const submit = ButtonHarness.getByText('Submit');
  await submit.click();

  const alert = AlertHarness.first();
  expect(alert.getSeverity()).toBe('success');
  expect(alert.getText()).toContain('Saved');
});

Available harnesses

| Harness | MUI Component | Selector | |---|---|---| | AccordionHarness | Accordion | .MuiAccordion-root | | AlertHarness | Alert | .MuiAlert-root | | AutocompleteHarness | Autocomplete | .MuiAutocomplete-inputRoot | | AvatarHarness | Avatar | .MuiAvatar-root | | BadgeHarness | Badge | .MuiBadge-root | | BreadcrumbsHarness | Breadcrumbs | .MuiBreadcrumbs-root | | ButtonGroupHarness | ButtonGroup | .MuiButtonGroup-root | | ButtonHarness | Button | .MuiButtonBase-root | | CardHarness | Card | .MuiCard-root | | CheckboxHarness | Checkbox | .MuiCheckbox-root | | ChipHarness | Chip | .MuiChip-root | | CircularProgressHarness | CircularProgress | .MuiCircularProgress-root | | DialogHarness | Dialog | .MuiDialog-root | | DividerHarness | Divider | .MuiDivider-root | | DrawerHarness | Drawer | .MuiDrawer-root | | IconButtonHarness | IconButton | .MuiIconButton-root | | IconHarness | SvgIcon | .MuiSvgIcon-root | | LinearProgressHarness | LinearProgress | .MuiLinearProgress-root | | LinkHarness | Link | .MuiLink-root | | ListItemHarness | ListItem | .MuiListItem-root | | MenuHarness | Menu | .MuiMenu-root | | MenuItemHarness | MenuItem | .MuiMenuItem-root | | PaginationHarness | Pagination | .MuiPagination-root | | PaperHarness | Paper | .MuiPaper-root | | PopoverHarness | Popover | .MuiPopover-root | | RadioGroupHarness | RadioGroup | [role="radiogroup"] | | SelectHarness | Select | .MuiSelect-select | | SkeletonHarness | Skeleton | .MuiSkeleton-root | | SliderHarness | Slider | .MuiSlider-root | | SnackbarHarness | Snackbar | .MuiSnackbar-root | | SwitchHarness | Switch | .MuiSwitch-root | | TabHarness | Tab | .MuiTab-root | | TableCellHarness | TableCell | .MuiTableCell-root | | TableContainerHarness | TableContainer | .MuiTableContainer-root | | TableRowHarness | TableRow | .MuiTableRow-root | | TabsHarness | Tabs | .MuiTabs-root | | TextFieldHarness | TextField | .MuiInputBase-root | | ToggleButtonHarness | ToggleButton | .MuiToggleButton-root | | TooltipHarness | Tooltip | .MuiTooltip-popper | | TypographyHarness | Typography | .MuiTypography-root |

All harnesses inherit the static methods from DomHarness: first(), all(), find(), match(), and fromDomElement(). Several also provide convenience finders like getByText() or getByName().

Building your own harnesses

Compose MUI harnesses inside a page- or feature-level harness. See Best Practices for full guidance.

import { DomHarness } from 'dom-harness';
import { ButtonHarness, TextFieldHarness, AlertHarness } from 'mui-harness';

class LoginFormHarness extends DomHarness {
  static testid = 'login-form';

  get email() {
    return TextFieldHarness.getByName('email', this.root);
  }

  get password() {
    return TextFieldHarness.getByName('password', this.root);
  }

  get submit() {
    return ButtonHarness.getByText('Log in', this.root);
  }

  get error() {
    return AlertHarness.first(this.root);
  }
}

Testing setup

vitest.config.ts

import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/setupTests.ts'],
    css: false,
  },
});

setupTests.ts

import '@testing-library/jest-dom/vitest';