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

3 1 1

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

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed
  • 2:34 --only-changed
  • 4:27 --repeat-each
  • 5:15 --forbid-only
  • 5:51 --ui --headed --workers 1

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Top comments (1)

Collapse
 
kasim_nalawala_8b6df4c77b profile image
Kasim Nalawala β€’

Insightful, thank you Mr. Ikram for sharing πŸ˜€

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

πŸ‘‹ Kindness is contagious

If you appreciated this article, feel free to show some love with a ❀️ or share your thoughts in the comments!

Join our community of passionate developers!