Skip to content

Latest commit

 

History

History
127 lines (102 loc) · 4.3 KB

File metadata and controls

127 lines (102 loc) · 4.3 KB

ContractDetailPage Test Fix - Summary

Problem

After upgrading to Next.js 15.5.18, the ContractDetailPage test was failing with:

An unsupported type was passed to use(): [object Object]

This was caused by the component trying to use React.use() on params that weren't properly wrapped in a Promise or Suspense boundary during testing.

Root Cause

In Next.js 15, route parameters are passed as Promise<{ id: string }>, and the component needed to handle this asynchronously. However:

  1. Using React.use() in a client component with params requires a Suspense boundary
  2. Testing an async component that uses React.use() with promises is complex in Jest
  3. The component lifecycle didn't align with test expectations

Solution

Converted the component to an async Server Component instead of a client component:

Changes Made to src/app/contracts/[id]/page.tsx:

  1. Removed 'use client' directive - Made it a server component to use async/await natively
  2. Removed React imports - No longer needed for client-side state management
  3. Changed from sync to async - const ContractDetailPage = async ({ params }: ContractDetailPageProps) => {
  4. Used await directly - const { id } = await params; instead of React.use(params)
  5. Simplified component logic - No need for useState or useEffect since it's server-side

Changes Made to src/app/contracts/[id]/__tests__/page.test.tsx:

  1. Updated test to await the component - const Component = await ContractDetailPage({ params });
  2. Added React import back - Needed for JSX in test
  3. Passed Promise to params - const params = Promise.resolve({ id: '123' });

Before and After

Before (Client Component):

'use client';

import React from 'react';

const ContractDetailPage = ({ params }: { params: Promise<{ id: string }> }) => {
  const { id } = React.use(params); // ❌ Issues with testing
  // ...
};

After (Server Component):

// No 'use client' directive

const ContractDetailPage = async ({ params }: { params: Promise<{ id: string }> }) => {
  const { id } = await params; // ✅ Native async/await
  // ...
};

Test Before:

it('renders the contract overview and action panel', () => {
  const params = { id: '123' };
  render(<ContractDetailPage params={params} />); // ❌ Test fails
  // ...
});

Test After:

it('renders the contract overview and action panel', async () => {
  const params = Promise.resolve({ id: '123' });
  const Component = await ContractDetailPage({ params }); // ✅ Properly awaits
  render(Component);
  // ...
});

Benefits of This Approach

  1. More idiomatic - Uses native async/await instead of React.use()
  2. Better performance - Server component, no unnecessary client-side rendering
  3. Testable - Async function is easy to test in Jest
  4. Type-safe - Full TypeScript support
  5. Future-proof - Aligns with Next.js 15+ best practices

Verification Results

Tests: All 165 tests passing

Tests: 165 passed, 165 total

Build: Successful compilation

npm run build - Success
.next folder generated

Linting: No errors or warnings

npm run lint - No ESLint warnings or errors

Specific Test: ContractDetailPage test passing

PASS src/app/contracts/[id]/__tests__/page.test.tsx
  ContractDetailPage
    ✓ renders the contract overview and action panel

Files Modified

  • src/app/contracts/[id]/page.tsx - Converted to async server component
  • src/app/contracts/[id]/__tests__/page.test.tsx - Updated to test async component

Migration Pattern for Other Pages

If you have other Next.js 15 page components that need similar fixes:

  1. Check if the component can be a Server Component (doesn't need client-side interactivity)
  2. Remove 'use client' directive
  3. Change function signature to async
  4. Replace React.use(params) with await params
  5. Update tests to await the component invocation

Impact

  • ✅ Zero breaking changes to component API
  • ✅ Zero impact on user experience
  • ✅ All functionality preserved
  • ✅ Better alignment with Next.js 15 patterns

Conclusion

The test failure has been completely resolved by adopting Next.js 15's native async Server Components pattern. The component is now more maintainable, testable, and performant.