import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import sdk from '@farcaster/miniapp-sdk'; import { renderHook, waitFor } from '@testing-library/react'; import { act } from 'react'; import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest'; import { useComposeCast } from './useComposeCast'; const composeCastMock = { success: true, }; vi.mock('@farcaster/miniapp-sdk', () => ({ default: { actions: { composeCast: vi.fn(), }, }, })); const createWrapper = () => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); // eslint-disable-next-line react/display-name return ({ children }: { children: React.ReactNode }) => ( {children} ); }; describe('useComposeCast', () => { beforeEach(() => { (sdk.actions.composeCast as Mock).mockResolvedValue(composeCastMock); vi.clearAllMocks(); }); it('should return composeCast and composeCastAsync functions', () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); expect(typeof result.current.composeCast).toBe('function'); expect(typeof result.current.composeCastAsync).toBe('function'); }); it('should call sdk.actions.composeCast when composeCast is executed', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); await act(async () => { result.current.composeCast({ text: 'Hello world!' }); }); await waitFor(() => { expect(sdk.actions.composeCast).toHaveBeenCalledWith({ text: 'Hello world!', }); }); }); it('should call sdk.actions.composeCast when composeCastAsync is executed', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); await act(async () => { await result.current.composeCastAsync({ text: 'Hello world!' }); }); expect(sdk.actions.composeCast).toHaveBeenCalledWith({ text: 'Hello world!', }); }); it('should pass all parameters correctly without close', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); const params = { text: 'Hello world!', embeds: ['https://example.com'] as [string], parent: { type: 'cast' as const, hash: '0x123', }, channelKey: 'test-channel', }; await act(async () => { result.current.composeCast(params); }); await waitFor(() => { expect(sdk.actions.composeCast).toHaveBeenCalledWith(params); }); }); it('should handle embeds with maximum two items', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); const params = { text: 'Hello world!', embeds: ['https://example.com', 'https://example2.com'] as [ string, string, ], }; await act(async () => { result.current.composeCast(params); }); await waitFor(() => { expect(sdk.actions.composeCast).toHaveBeenCalledWith(params); }); }); it('should handle empty embeds array', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); const params = { text: 'Hello world!', embeds: [] as [], }; await act(async () => { result.current.composeCast(params); }); await waitFor(() => { expect(sdk.actions.composeCast).toHaveBeenCalledWith(params); }); }); it('should return the compose cast result on success', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); let response; await act(async () => { response = await result.current.composeCastAsync({ text: 'Hello world!', }); }); expect(response).toBe(composeCastMock); }); it('should handle errors when composeCast fails', async () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(vi.fn()); (sdk.actions.composeCast as Mock).mockRejectedValue( new Error('Compose failed'), ); const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); await act(async () => { result.current.composeCast({ text: 'Hello world!' }); }); await waitFor(() => { expect(result.current.isError).toBe(true); }); consoleSpy.mockRestore(); }); it('should handle mutation states correctly', async () => { const { result } = renderHook(() => useComposeCast(), { wrapper: createWrapper(), }); expect(result.current.isPending).toBe(false); expect(result.current.isError).toBe(false); expect(result.current.isSuccess).toBe(false); act(() => { result.current.composeCast({ text: 'Hello world!' }); }); await waitFor(() => { expect(result.current.isSuccess).toBe(true); }); }); });