Should I test that?

Should I test component props?

Verdict

No

No, do not write a test for each prop of a component: props that only set content or style need none, because TypeScript checks them and the author sees them on screen, and each prop that changes behaviour, such as a callback or a disabled flag, gets one interaction test.

Why

Do not write a test for each prop; test the props that change behaviour. The typical case is a presentational React component in a TypeScript app, such as a profile card with name, avatarUrl and variant, which its author opens in Storybook after each change. Blast radius is users and Change frequency is regularly, about once a month for product components. Detectability is immediately and Reversibility is trivial: TypeScript rejects a missing prop, the author sees a display prop on screen, and a revert leaves nothing behind. Test cost is moderate, because tests for eight props take about an hour and break on markup edits, so rule R8 gives Do not test. For a callback prop, Detectability moves to same-day and the decision becomes Test minimally.

When the decision changes
WhenDecisionWhy
The prop is a callback, such as `onSave`, that the component calls on a clickTest minimally: one user-event test that asserts the arguments the callback receivesDetectability moves to same-day, because a dead button looks unchanged and a customer reports it
The props feed data that the app saves, such as `initialValues` of a formTest: assert the submitted payload for the main path and each optional fieldDetectability moves to eventually and Reversibility to with-effort, because a dropped value shows nothing and saved records need a repair script
A layout component forwards two props of one type, such as `startDate` and `endDate`, to a date pickerTest minimally: pass a distinct date to each prop and check which field shows eachDetectability moves to eventually, because a swapped prop renders a plausible date
A shared design-system Button gets its props from dozens of screens that other teams ownTest minimally: one interaction test for each prop that changes behaviour, such as `type` and `disabled`Change frequency falls to rarely and Detectability moves to eventually, because a break shows on screens its author never opens
The component formats a price prop, such as an amount in cents on an order summaryTest mandatory: assert the exact string for each currency and rounding caseBlast radius rises to money and Reversibility to costly, because customers buy at the amount shown

What breaks if you don't test

For display props, nothing breaks that the author misses. The failures that get through are props whose effect nobody sees: a component stops calling onSave, a shared Button drops the type it receives, or a layout component swaps two dates on the way to a child. The screen looks the same, so the first person to notice is a customer.

What you lose if you over-test

A test for each display prop repeats the JSX: render with name="Ana", assert that "Ana" appears. A card with eight props gets eight such tests, and a redesign that moves the name into a tooltip breaks all eight with no bug behind them. A card that passes onSelect straight to a button shows full coverage from render tests alone, although no test clicks it.

What to do instead

Sort props by what they do, and write Testing Library unit tests only where a prop changes behaviour:

  1. Props the user acts through, such as onChange, disabled and type: one user-event test each, asserting the callback's arguments or that nothing fires.
  2. Two or more forwarded props of one type: one test with a distinct value in each.
  3. Props that only set content or style: type them, as the React TypeScript guide shows, and look at the result.

Query by role and label, per the Testing Library guiding principles, so a markup change that keeps the behaviour passes.

When the answer changes

  • The component is shared across many screens that other teams own.
  • A prop carries data that the app saves, or a price.
  • The codebase has no prop types, so a renamed prop arrives as undefined.

Real incident + Code example

The Add button that submitted the form

On a recruiting app I worked on, the design-system Button typed its props as the HTML button attributes plus variant and size, so TypeScript accepted type="button". The component passed only variant, size, onClick and children to the element, and a <button> inside a form with no type is a submit button. "Add phone number" in the candidate form submitted and closed the form before the new row was filled in. Storybook shows the button with no form around it, and the first report came from a recruiter four days later. The fix passed the remaining props through, and this test joined the Button suite:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect, test, vi } from 'vitest';
import { Button } from './Button';

test('a Button with type="button" does not submit its form', async () => {
  const user = userEvent.setup();
  const onSubmit = vi.fn((event) => event.preventDefault());
  render(
    <form onSubmit={onSubmit}>
      <Button type="button">Add phone number</Button>
    </form>,
  );

  await user.click(screen.getByRole('button', { name: 'Add phone number' }));

  expect(onSubmit).not.toHaveBeenCalled();
});

The suite has no test for variant or size, because a wrong colour shows as soon as someone opens the story.

FAQ

Should I test all component props?

No, test only the props that change what the component does, such as callbacks, disabled and type, with one interaction test each. Props that only set text or style need no test in a TypeScript codebase.

Should I test that a component passes props to its children?

No, a component that passes props of different types to children with their own tests needs no forwarding test, because TypeScript rejects a prop of the wrong type. Add one test when two props of one type pass through, because a swap renders a plausible value.

Does TypeScript replace tests for component props?

TypeScript replaces tests that check whether a prop is present and has the right type. A callback that the component never calls and a prop that it accepts and drops both compile, so each prop that changes behaviour still needs one interaction test.