Hone logo
Hone
Problems

Mastering React Context API Testing with Jest in TypeScript

Testing React components that utilize the Context API can be tricky. This challenge focuses on writing robust Jest tests for a component that consumes a React Context, ensuring that the component correctly accesses and displays context data. Mastering this skill is crucial for building scalable and maintainable React applications.

Problem Description

You are tasked with testing a React component, UserProfileDisplay, which consumes a UserContext. This context provides the userName and userEmail. Your goal is to write Jest tests using @testing-library/react to verify that UserProfileDisplay correctly renders the user's name and email when they are available in the context.

Requirements:

  • Create a mock UserContext and a MockUserProvider component for testing purposes.
  • The MockUserProvider should accept userName and userEmail as props and provide them through the UserContext.Provider.
  • Write Jest tests for the UserProfileDisplay component.
  • Tests should cover scenarios where the context data is present and where it is absent (resulting in default or null values).
  • Use render from @testing-library/react to render the component within the MockUserProvider.

Expected Behavior:

  • When userName and userEmail are provided in the context, UserProfileDisplay should render them accurately.
  • If userName or userEmail are not provided (e.g., undefined or null), the component should render appropriate fallback text (e.g., "Guest" for name, "N/A" for email).

Edge Cases to Consider:

  • What happens when the context provides null or undefined values for userName and userEmail?
  • What happens if the UserProfileDisplay component is rendered without any UserContext.Provider above it (although your tests should prevent this by using MockUserProvider)?

Examples

Example 1: User Data Present

// Assume these are defined in your application
// src/contexts/UserContext.ts
import React from 'react';

interface UserContextType {
  userName: string | null;
  userEmail: string | null;
}

export const UserContext = React.createContext<UserContextType | undefined>(undefined);

// src/components/UserProfileDisplay.tsx
import React, { useContext } from 'react';
import { UserContext } from '../contexts/UserContext';

export const UserProfileDisplay: React.FC = () => {
  const context = useContext(UserContext);
  const userName = context?.userName ?? 'Guest';
  const userEmail = context?.userEmail ?? 'N/A';

  return (
    <div>
      <p>Name: {userName}</p>
      <p>Email: {userEmail}</p>
    </div>
  );
};

Test Setup:

// src/tests/UserProfileDisplay.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import { UserContext } from '../contexts/UserContext';
import { UserProfileDisplay } from '../components/UserProfileDisplay';

// Mock Provider for testing
const MockUserProvider: React.FC<{ children: React.ReactNode; userName?: string | null; userEmail?: string | null }> = ({
  children,
  userName = 'Alice',
  userEmail = 'alice@example.com',
}) => {
  return (
    <UserContext.Provider value={{ userName, userEmail }}>
      {children}
    </UserContext.Provider>
  );
};

// Test case
test('should display user name and email when provided in context', () => {
  render(
    <MockUserProvider userName="Alice" userEmail="alice@example.com">
      <UserProfileDisplay />
    </MockUserProvider>
  );

  expect(screen.getByText('Name: Alice')).toBeInTheDocument();
  expect(screen.getByText('Email: alice@example.com')).toBeInTheDocument();
});

Output: The test passes if the rendered component shows "Name: Alice" and "Email: alice@example.com".

Example 2: User Data Missing (Null/Undefined)

// Using the same UserContext and UserProfileDisplay as in Example 1

// Test setup (within src/tests/UserProfileDisplay.test.tsx)
test('should display default values when context data is null or undefined', () => {
  render(
    <MockUserProvider userName={null} userEmail={undefined}>
      <UserProfileDisplay />
    </MockUserProvider>
  );

  expect(screen.getByText('Name: Guest')).toBeInTheDocument();
  expect(screen.getByText('Email: N/A')).toBeInTheDocument();
});

test('should display default values when context is missing entirely (though MockUserProvider prevents this)', () => {
  // This test demonstrates the fallback logic if context is truly undefined
  // In practice, your tests will wrap components in MockUserProvider
  render(
    // Rendering without any provider, relying on UserContext's default undefined
    <UserContext.Provider value={undefined}>
      <UserProfileDisplay />
    </UserContext.Provider>
  );

  expect(screen.getByText('Name: Guest')).toBeInTheDocument();
  expect(screen.getByText('Email: N/A')).toBeInTheDocument();
});

Output: The tests pass if the rendered component shows "Name: Guest" and "Email: N/A" in both scenarios.

Constraints

  • Language: TypeScript
  • Testing Framework: Jest
  • React Testing Library: @testing-library/react
  • Dependencies: Ensure @testing-library/jest-dom is configured for better matchers.
  • Component Structure: Assume the UserProfileDisplay component and UserContext are structured as shown in the examples. You need to provide the test file.

Notes

  • Consider using screen.getByText and toBeInTheDocument from @testing-library/jest-dom for clear assertions.
  • The MockUserProvider is a key element for controlling the context provided to your component during tests.
  • Think about how to structure your tests to cover both the happy path (data present) and the edge cases (data missing).
  • You will need to create the MockUserProvider component and the test file (UserProfileDisplay.test.tsx). You can assume the existence of UserContext.ts and UserProfileDisplay.tsx as described.
Loading editor...
typescript