import React from 'react'; import { render } from '@testing-library/react'; import { ConvexProviderWithClerk } from 'convex/react-clerk'; import { ClerkProvider } from '@clerk/nextjs'; import { ConvexReactClient } from 'convex/react'; import { vi } from 'vitest'; // Mock Convex client for testing with better type safety export const createMockConvexClient = () => { const mockClient = { query: vi.fn().mockResolvedValue(null), mutation: vi.fn().mockResolvedValue(null), action: vi.fn().mockResolvedValue(null), subscribe: vi.fn().mockReturnValue({ localQueryResult: vi.fn(), journal: vi.fn(), onUpdate: vi.fn(), onTransition: vi.fn(), }), // Additional methods that may be used by Convex React hooks connectionState: vi.fn().mockReturnValue({ isWebSocketConnected: true }), watchQuery: vi.fn().mockReturnValue({ localQueryResult: vi.fn().mockReturnValue({ status: 'success', value: null }), journal: vi.fn().mockReturnValue({ queries: [], mutations: [] }), onUpdate: vi.fn(), onTransition: vi.fn(), }), localQueryResult: vi.fn().mockReturnValue({ status: 'success', value: null }), // Cleanup methods close: vi.fn(), clearAuth: vi.fn(), setAuth: vi.fn(), } as unknown as ConvexReactClient; return mockClient; }; // Type definition for auth state type AuthState = { isLoaded: boolean; isSignedIn: boolean; userId: string | null; sessionId: string | null; orgId: string | null; orgRole: string | null; getToken: () => Promise; }; // Mock useAuth hook for Clerk integration with better defaults const createMockUseAuth = (overrides?: Partial): (() => AuthState) => { const defaultAuth: AuthState = { isLoaded: true, isSignedIn: false, userId: null, sessionId: null, orgId: null, orgRole: null, getToken: vi.fn().mockResolvedValue(null), }; return () => ({ ...defaultAuth, ...overrides }); }; // Export the default mock for backward compatibility export const mockUseAuth: () => AuthState = createMockUseAuth(); // Test providers wrapper that matches the real app structure interface TestProvidersProps { children: React.ReactNode; convexClient?: ConvexReactClient; clerkPublishableKey?: string; // Add authentication state control for testing authState?: { isSignedIn?: boolean; userId?: string; sessionId?: string; }; } export const TestProviders: React.FC = ({ children, convexClient = createMockConvexClient(), clerkPublishableKey = "pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA", authState = {} }) => { // Create custom auth mock based on provided state const useAuthMock = createMockUseAuth({ isSignedIn: authState.isSignedIn ?? false, userId: authState.userId ?? null, sessionId: authState.sessionId ?? null, }); return ( {children} ); }; // Custom render function that includes providers // This is the main function tests should use to render components export const renderWithProviders = ( ui: React.ReactElement, { convexClient, clerkPublishableKey, authState, ...options }: { convexClient?: ConvexReactClient; clerkPublishableKey?: string; authState?: { isSignedIn?: boolean; userId?: string; sessionId?: string; }; } & Parameters[1] = {} ) => { const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); return render(ui, { wrapper: Wrapper, ...options }); }; // Helper to render with authenticated user export const renderWithAuth = ( ui: React.ReactElement, userOptions: { userId?: string; sessionId?: string; } = {}, renderOptions?: Parameters[1] ) => { return renderWithProviders(ui, { authState: { isSignedIn: true, userId: userOptions.userId ?? "test-user-id", sessionId: userOptions.sessionId ?? "test-session-id", }, ...renderOptions, }); }; // Helper to render with unauthenticated user export const renderWithoutAuth = ( ui: React.ReactElement, renderOptions?: Parameters[1] ) => { return renderWithProviders(ui, { authState: { isSignedIn: false, userId: undefined, sessionId: undefined, }, ...renderOptions, }); }; // Helper to create a mock with specific behavior for testing export const createMockConvexClientWithBehavior = (behavior: { queryResults?: Record; mutationResults?: Record; actionResults?: Record; }) => { const mockClient = createMockConvexClient(); // Setup query mock behavior if (behavior.queryResults) { mockClient.query = vi.fn().mockImplementation((functionName: string, args: any) => { const key = `${functionName}:${JSON.stringify(args)}`; return Promise.resolve(behavior.queryResults?.[key] ?? null); }); } // Setup mutation mock behavior if (behavior.mutationResults) { mockClient.mutation = vi.fn().mockImplementation((functionName: string, args: any) => { const key = `${functionName}:${JSON.stringify(args)}`; return Promise.resolve(behavior.mutationResults?.[key] ?? null); }); } // Setup action mock behavior if (behavior.actionResults) { mockClient.action = vi.fn().mockImplementation((functionName: string, args: any) => { const key = `${functionName}:${JSON.stringify(args)}`; return Promise.resolve(behavior.actionResults?.[key] ?? null); }); } return mockClient; };