import { renderHook } from '@testing-library/react';
import { act } from 'react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { MiniKitContext } from '../MiniKitProvider';
import type { MiniKitContextType } from '../types';
import { useMiniKit } from './useMiniKit';
const mockContext = {
enabled: true,
context: null,
notificationProxyUrl: '/api/notify',
updateClientContext: vi.fn(),
__isMiniKit: true,
} as MiniKitContextType;
const mockDisabledContext = {
enabled: false,
context: null,
notificationProxyUrl: '/api/notify',
updateClientContext: vi.fn(),
__isMiniKit: false,
} as MiniKitContextType;
vi.mock('@/DefaultOnchainKitProviders', () => ({
DefaultOnchainKitProviders: ({ children }: { children: React.ReactNode }) =>
children,
}));
vi.mock('@/OnchainKitProvider', () => ({
OnchainKitProvider: ({ children }: { children: React.ReactNode }) => children,
}));
vi.mock('@farcaster/miniapp-wagmi-connector', () => ({
farcasterMiniApp: vi.fn(),
}));
describe('useMiniKit', () => {
afterEach(() => {
vi.clearAllMocks();
});
it('should throw error when MiniKit is not enabled', () => {
expect(() => {
renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
}).toThrow('MiniKit is not enabled. Please check your OnchainKitProvider.');
});
it('allows users to pass through ready options', async () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
await act(async () => {
result.current.setFrameReady({ disableNativeGestures: true });
});
expect(result.current.isFrameReady).toBe(true);
});
it('should return the correct values', () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
expect(result.current.isFrameReady).toBe(false);
expect(result.current.context).toEqual(mockContext.context);
expect(result.current.notificationProxyUrl).toBe(
mockContext.notificationProxyUrl,
);
});
it('should set ready', async () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
await act(async () => {
result.current.setFrameReady();
});
expect(result.current.isFrameReady).toBe(true);
});
// Tests for new properties
it('allows users to pass through ready options with setMiniAppReady', async () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
await act(async () => {
result.current.setMiniAppReady({ disableNativeGestures: true });
});
expect(result.current.isMiniAppReady).toBe(true);
});
it('should return the correct values for new properties', () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
expect(result.current.isMiniAppReady).toBe(false);
expect(result.current.context).toEqual(mockContext.context);
expect(result.current.notificationProxyUrl).toBe(
mockContext.notificationProxyUrl,
);
});
it('should set mini app ready', async () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
await act(async () => {
result.current.setMiniAppReady();
});
expect(result.current.isMiniAppReady).toBe(true);
});
it('should ensure both deprecated and new properties are synchronized', async () => {
const { result } = renderHook(() => useMiniKit(), {
wrapper: ({ children }) => (
{children}
),
});
// Test that both properties start false
expect(result.current.isFrameReady).toBe(false);
expect(result.current.isMiniAppReady).toBe(false);
// Set ready using deprecated method
await act(async () => {
result.current.setFrameReady();
});
// Both should be true since they reference the same state
expect(result.current.isFrameReady).toBe(true);
expect(result.current.isMiniAppReady).toBe(true);
});
});