DEV Community

Jagoda Bieniek
Jagoda Bieniek

Posted on

How to Test stopPropagation() in React Testing Library

πŸš€ Introduction

Ensuring stopPropagation() works correctly in React applications is crucial when handling nested click events. Instead of checking if stopPropagation() was explicitly called, the best approach is to test its effectβ€”whether the event propagates or not.

This article explores:

βœ… The best approach to testing stopPropagation() (checking event propagation).

βœ… An alternative method using event mocking.

βœ… Which method is better and when to use each approach.

πŸ›  Best Approach: Testing the Effect of stopPropagation()

The recommended way to test stopPropagation() is to wrap the tested component inside a parent <div> with an onClick handler and check whether the event reaches the parent.

Example: Testing Propagation Prevention

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { FormElementsList } from "@/components/FormElementsList";

it("stops propagation when an element is clicked", async () => {
  const onOuterClick = jest.fn();

  render(
    <div onClick={onOuterClick}>
      <FormElementsList elementsList={[{ name: "Text Input", type: "text", icon: <span>πŸ“</span> }]} />
    </div>
  );

  const textInputElement = screen.getByText("Text Input");
  await userEvent.click(textInputElement);

  expect(onOuterClick).toHaveBeenCalledTimes(0); // Ensures event does not propagate
});
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Why This Works ?

  • The parent <div> has an onClick handler (onOuterClick).

  • If stopPropagation() is correctly applied inside FormElementsList, clicking on an element should not trigger onOuterClick.

  • The assertion expect(onOuterClick).toHaveBeenCalledTimes(0) ensures the event was stopped successfully.

πŸ›  Alternative: Mocking stopPropagation()

If you need to directly verify that stopPropagation() was called, you can mock the event and track the function call.

Example: Mocking stopPropagation()

import { render, screen } from "@testing-library/react";
import { FormElementsList } from "@/components/FormElementsList";

it("calls stopPropagation when an element is clicked", async () => {
  render(<FormElementsList elementsList={[{ name: "Text Input", type: "text", icon: <span>πŸ“</span> }]} />);

  const textInputElement = screen.getByText("Text Input");

  const event = new MouseEvent("click", { bubbles: true });
  jest.spyOn(event, "stopPropagation");

  textInputElement.dispatchEvent(event);

  expect(event.stopPropagation).toHaveBeenCalled();
});
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Why This Works ?

  • jest.spyOn(event, "stopPropagation") tracks whether the function is called.

  • dispatchEvent(event) manually triggers the click event.

  • expect(event.stopPropagation).toHaveBeenCalled() ensures stopPropagation() was executed.

πŸ›  Which Method Should You Use?

Method βœ… Pros ❌ Cons
1. Testing Effect (Wrapper <div>) Tests real user behavior Doesn’t confirm stopPropagation() was explicitly called
2. Mocking stopPropagation() Confirms stopPropagation() is called Tests implementation rather than behavior

πŸš€ Recommended Approach

Prioritize testing real behavior over implementation details for better maintainability!

πŸ’¬ Have you used different methods for testing event propagation? Share your thoughts in the comments!

Top comments (0)