import { render, screen } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import React from 'react'; import type { EvmUiKitManagerState } from '../../evmUiKitManager'; /** * Regression coverage for a white screen when switching wallet kit at runtime. * * uiKitManager.configure() deliberately clears kitProviderComponent and * isKitAssetsLoaded and notifies listeners *before* RainbowKit's dynamically * imported provider resolves. During that window the kit is already 'rainbowkit' * but the provider is absent, so rendering children mounted RainbowKit consumers * outside RainbowKitProvider and threw: * * Uncaught Error: Transaction hooks must be used within RainbowKitProvider */ let mockState: EvmUiKitManagerState; vi.mock('wagmi', () => ({ WagmiProvider: ({ children }: React.PropsWithChildren) =>
{children}
, })); vi.mock('@tanstack/react-query', () => ({ QueryClient: class {}, QueryClientProvider: ({ children }: React.PropsWithChildren) =>
{children}
, })); vi.mock('@openzeppelin/adapter-evm-core', () => ({ WagmiProviderInitializedContext: { Provider: ({ children }: React.PropsWithChildren) => children, }, })); vi.mock('../../evmUiKitManager', () => ({ evmUiKitManager: { getState: () => mockState, subscribe: () => () => {}, }, })); const { EvmWalletUiRoot } = await import('../EvmWalletUiRoot'); function stateWith(overrides: Partial): EvmUiKitManagerState { return { wagmiConfig: { mock: true }, kitProviderComponent: null, isKitAssetsLoaded: false, currentFullUiKitConfig: null, error: null, ...overrides, } as unknown as EvmUiKitManagerState; } const RkProvider = ({ children }: React.PropsWithChildren) => (
{children}
); describe('EvmWalletUiRoot RainbowKit provider gating', () => { beforeEach(() => { mockState = stateWith({}); }); it('withholds children while the RainbowKit provider is still loading', () => { mockState = stateWith({ currentFullUiKitConfig: { kitName: 'rainbowkit', kitConfig: {} }, kitProviderComponent: null, isKitAssetsLoaded: false, }); render( wallet ui ); // Rendering the child here is what threw outside RainbowKitProvider. expect(screen.queryByTestId('child')).toBeNull(); }); it('withholds children when assets report loaded but the provider is missing', () => { mockState = stateWith({ currentFullUiKitConfig: { kitName: 'rainbowkit', kitConfig: {} }, kitProviderComponent: null, isKitAssetsLoaded: true, }); render( wallet ui ); expect(screen.queryByTestId('child')).toBeNull(); }); it('renders children inside RainbowKitProvider once it is ready', () => { mockState = stateWith({ currentFullUiKitConfig: { kitName: 'rainbowkit', kitConfig: {} }, kitProviderComponent: RkProvider, isKitAssetsLoaded: true, }); render( wallet ui ); expect(screen.getByTestId('rk-provider')).toBeTruthy(); expect(screen.getByTestId('child')).toBeTruthy(); }); it('renders children immediately for non-RainbowKit kits', () => { mockState = stateWith({ currentFullUiKitConfig: { kitName: 'custom', kitConfig: {} }, }); render( wallet ui ); expect(screen.getByTestId('child')).toBeTruthy(); expect(screen.queryByTestId('rk-provider')).toBeNull(); }); });