Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions packages/onchainkit/src/DefaultOnchainKitProviders.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { QueryClient } from '@tanstack/react-query';
import { render, screen } from '@testing-library/react';
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest';
import { http, WagmiProvider, createConfig } from 'wagmi';
import { http, createConfig } from 'wagmi';
import { DefaultOnchainKitProviders } from './DefaultOnchainKitProviders';
import { useProviderDependencies } from './internal/hooks/useProviderDependencies';

Expand Down Expand Up @@ -49,8 +49,8 @@ vi.mock('./internal/hooks/useProviderDependencies', () => ({
describe('DefaultOnchainKitProviders', () => {
beforeEach(() => {
(useProviderDependencies as Mock).mockReturnValue({
providedWagmiConfig: false,
providedQueryClient: false,
providedWagmiConfig: null,
providedQueryClient: null,
});
});

Expand All @@ -66,39 +66,54 @@ describe('DefaultOnchainKitProviders', () => {
expect(screen.queryAllByTestId('query-client-provider')).toHaveLength(1);
});

it('should not render duplicate default providers when a wagmi provider already exists', () => {
it('should not render duplicate WagmiProvider when a wagmi provider already exists', () => {
(useProviderDependencies as Mock).mockReturnValue({
providedWagmiConfig: wagmiConfig,
providedQueryClient: null,
});

render(
<WagmiProvider config={wagmiConfig}>
<DefaultOnchainKitProviders>
<div>Test Child</div>
</DefaultOnchainKitProviders>
</WagmiProvider>,
<DefaultOnchainKitProviders>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

expect(screen.getByText('Test Child')).toBeInTheDocument();
expect(screen.queryAllByTestId('wagmi-provider')).toHaveLength(1);
expect(screen.queryAllByTestId('wagmi-provider')).toHaveLength(0);
expect(screen.queryAllByTestId('query-client-provider')).toHaveLength(1);
});

it('should not render duplicate default providers when a query client already exists', () => {
it('should not render duplicate QueryClientProvider when a query client already exists', () => {
(useProviderDependencies as Mock).mockReturnValue({
providedWagmiConfig: null,
providedQueryClient: queryClient,
});

render(
<QueryClientProvider client={queryClient}>
<DefaultOnchainKitProviders>
<div>Test Child</div>
</DefaultOnchainKitProviders>
</QueryClientProvider>,
<DefaultOnchainKitProviders>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

expect(screen.getByText('Test Child')).toBeInTheDocument();
expect(screen.queryAllByTestId('query-client-provider')).toHaveLength(1);
expect(screen.queryAllByTestId('wagmi-provider')).toHaveLength(1);
expect(screen.queryAllByTestId('query-client-provider')).toHaveLength(0);
});

it('should not render any default providers when both providers already exist', () => {
(useProviderDependencies as Mock).mockReturnValue({
providedWagmiConfig: wagmiConfig,
providedQueryClient: queryClient,
});

render(
<DefaultOnchainKitProviders>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

expect(screen.getByText('Test Child')).toBeInTheDocument();
expect(screen.queryAllByTestId('wagmi-provider')).toHaveLength(0);
expect(screen.queryAllByTestId('query-client-provider')).toHaveLength(0);
});
});
79 changes: 48 additions & 31 deletions packages/onchainkit/src/DefaultOnchainKitProviders.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { type PropsWithChildren, useMemo } from 'react';
import { WagmiProvider } from 'wagmi';
import { Config, WagmiProvider } from 'wagmi';
import { coinbaseWallet } from 'wagmi/connectors';
import { createWagmiConfig } from './core/createWagmiConfig';
import type { CreateWagmiConfigParams } from './core/types';
Expand All @@ -23,37 +23,54 @@ export function DefaultOnchainKitProviders({
const { providedWagmiConfig, providedQueryClient } =
useProviderDependencies();

const defaultConfig = useMemo(() => {
// IMPORTANT: Don't create a new Wagmi configuration if one already exists
// This prevents the user-provided WagmiConfig from being overridden
return (
providedWagmiConfig ||
createWagmiConfig({
apiKey,
appName,
appLogoUrl,
connectors,
})
);
}, [apiKey, appName, appLogoUrl, connectors, providedWagmiConfig]);

const defaultQueryClient = useMemo(() => {
// IMPORTANT: Don't create a new QueryClient if one already exists
// This prevents the user-provided QueryClient from being overridden
return (
<WagmiProviderWithDefault
apiKey={apiKey}
appName={appName}
appLogoUrl={appLogoUrl}
connectors={connectors}
providedWagmiConfig={providedWagmiConfig}
>
<QueryClientProviderWithDefault providedQueryClient={providedQueryClient}>
{children}
</QueryClientProviderWithDefault>
</WagmiProviderWithDefault>
);
}

function WagmiProviderWithDefault({
apiKey,
appName,
appLogoUrl,
connectors,
children,
providedWagmiConfig,
}: PropsWithChildren<CreateWagmiConfigParams> & {
providedWagmiConfig: Config | null;
}) {
if (providedWagmiConfig) return children;

const config = createWagmiConfig({
apiKey,
appName,
appLogoUrl,
connectors,
});

return <WagmiProvider config={config}>{children}</WagmiProvider>;
}

function QueryClientProviderWithDefault({
children,
providedQueryClient,
}: PropsWithChildren<{ providedQueryClient: QueryClient | null }>) {
const queryClient = useMemo(() => {
return providedQueryClient || new QueryClient();
}, [providedQueryClient]);

// If both dependencies are missing, return a context with default parent providers
// If only one dependency is provided, expect the user to also provide the missing one
if (!providedWagmiConfig && !providedQueryClient) {
return (
<WagmiProvider config={defaultConfig}>
<QueryClientProvider client={defaultQueryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
);
}

return children;
if (providedQueryClient) return children;

return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}