DEV Community

Cover image for Unit/Component Testing React Apps: From 'Why Bother?' to 'Can't Live Without It'
Mohamed ikram
Mohamed ikram

Posted on • Edited on

2

Unit/Component Testing React Apps: From 'Why Bother?' to 'Can't Live Without It'

🚨 Anatomy of a 3 AM Production Crisis: A Testing Tale

🎭 The Scene:

// The innocent-looking code that ruined everyone's night
const getDomainUrl = (config: BackendConfig) => {
  return config.domain; // What could go wrong? Everything.
};
Enter fullscreen mode Exit fullscreen mode

🔍 Let's Debug Together: The Case of the Phantom Redirect

🚨 The Crime Scene

Dashboard users land at undefined/rest-path after a "harmless" config change

  • Suspect: A sneaky backend configuration tweak
  • Weapon: Missing validation for domain paths
  • Motive: "It worked in dev!" 🤦

Unit testing

describe('Domain Configuration', () => {
  it('should reject missing domain configuration', () => {
    const emptyConfig = {} as BackendConfig;
    expect(() => getDomainUrl(emptyConfig)).toThrow();
  });
});
Enter fullscreen mode Exit fullscreen mode

Code

const getDomainUrl = (config: BackendConfig): string => {
  if (!config.domain) {
    throw new DomainConfigError('Domain URL is required');
  }
  if (!isValidDomainUrl(config.domain)) {
    throw new DomainConfigError('Invalid domain URL format');
  }
  return config.domain;
};
Enter fullscreen mode Exit fullscreen mode

Component Testing

describe('RedirectHandler', () => {
  it('should handle domain configuration gracefully', () => {
    const mockConfig = {};
    const { getByTestId } = render(<RedirectHandler config={mockConfig} />);

    expect(getByTestId('config-error')).toBeInTheDocument();
    expect(captureError).toHaveBeenCalledWith(expect.any(DomainConfigError));
  });
});
Enter fullscreen mode Exit fullscreen mode

Code

const RedirectHandler: React.FC<{ config: BackendConfig }> = ({ config }) => {
  const [error, setError] = useState<string>();
  const navigate = useNavigate();

  useEffect(() => {
    try {
      const domainUrl = getDomainUrl(config);
      // Safely handle navigation
      navigate(`${domainUrl}/rest-path`);
    } catch (e) {
      if (e instanceof DomainConfigError) {
        setError(e.message);
        // Log to monitoring system
        captureError(e);
      }
    }
  }, [config, navigate]);

  if (error) {
    return (
      <ErrorBoundary>
        <ConfigurationError 
          message={error}
          retry={() => window.location.reload()}
        />
      </ErrorBoundary>
    );
  }

  return <LoadingSpinner />;
};
Enter fullscreen mode Exit fullscreen mode

🛠️ The Evolution of Robust Domain Configuration

🎯 What Changed?

  • Prevention Layers:

    • Custom error types (InvalidDomainException)
    • Domain validation before redirect logic
    • Error boundaries to catch misconfigurations
  • Test-First Approach:

    • Wrote failing test for missing config first
    • Added domain validation logic
    • Simulated edge cases (malformed URLs, empty configs)
  • Better Error UX:

    • User-friendly message: "Oops! We hit a snag – try again?"
    • Retry button with auto-logging for engineers
    • Integrated error tracking (Sentry/Datadog)

🚀 The Results

  • No more undefined redirects
  • Clear error tracking
  • Happy users (and developers who can sleep at night!)

🎯 The Tale of Two Developers: TDD vs. "We'll Test Later"

🐇 Bugs Bunny (Traditional):

  • 3 AM: Debugging while production burns
  • Result: Chasing midnight bugs, endless firefighting

⭐ Iron Man (TDD):

"Test first, code with confidence."

  • Result: Deploys and sleeps soundly
  • Secret Weapon: Tests act as code armor

🔄 The Real Difference:

Same deadline, drastically different outcomes.

While Bugs Bunny chases production bugs at midnight, Iron Man’s approach means:

🛡️ Prevention > Cure

  • Catches bugs before they reach production
  • Each test is a shield against future issues
  • No more 3 AM emergency fixes

🎯 Design That Makes Sense

  • Tests force you to think before coding
  • Code becomes naturally modular
  • Refactoring becomes a breeze

📚 Code That Tells a Story

  • Tests document how things should work
  • New team members get up to speed faster
  • Requirements are crystal clear

Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

Top comments (1)

Collapse
 
kasim_nalawala_8b6df4c77b profile image
Kasim Nalawala

Insightful, thank you Mr. Ikram for sharing 😀

Image of Datadog

Keep your GPUs in check

This cheatsheet shows how to use Datadog’s NVIDIA DCGM and Triton integrations to track GPU health, resource usage, and model performance—helping you optimize AI workloads and avoid hardware bottlenecks.

Get the Cheatsheet

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay