import { fireEvent, render, screen } from '@testing-library/react';
import { act } from 'react';
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest';
import {
type Config,
type UseAccountReturnType,
type UseConnectReturnType,
useAccount,
useConnect,
} from 'wagmi';
import { SwapButton } from './SwapButton';
import { useSwapContext } from './SwapProvider';
vi.mock('wagmi', () => ({
useAccount: vi.fn(),
useConnect: vi.fn(),
}));
vi.mock('./SwapProvider', () => ({
useSwapContext: vi.fn(),
}));
vi.mock('../../internal/components/Spinner', () => ({
Spinner: () =>
Loading...
,
}));
const useSwapContextMock = useSwapContext as Mock;
describe('SwapButton', () => {
const mockHandleSubmit = vi.fn();
beforeEach(() => {
mockHandleSubmit.mockClear();
});
it('should render button with text "Swap" when not loading', () => {
useSwapContextMock.mockReturnValue({
address: '0x123',
to: { loading: false, amount: 1, token: { name: 'ETH', address: '123' } },
from: {
loading: false,
amount: 1,
token: { name: 'BTC', address: '456' },
},
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
render();
const button = screen.getByTestId('ockSwapButton_Button');
expect(button).toHaveTextContent('Swap');
expect(button).not.toBeDisabled();
});
it('should render Spinner when loading', () => {
useSwapContextMock.mockReturnValue({
to: { loading: true, amount: 1, token: 'ETH' },
from: { loading: false, amount: 1, token: 'BTC' },
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
render();
const button = screen.getByTestId('ockSwapButton_Button');
expect(screen.getByTestId('spinner')).toBeInTheDocument();
expect(button).toBeDisabled();
});
it('should render Spinner when transaction is pending', () => {
useSwapContextMock.mockReturnValue({
to: { loading: false, amount: 1, token: 'ETH' },
from: { loading: false, amount: 1, token: 'BTC' },
lifecycleStatus: { statusName: 'transactionPending' },
handleSubmit: mockHandleSubmit,
});
render();
const button = screen.getByTestId('ockSwapButton_Button');
expect(screen.getByTestId('spinner')).toBeInTheDocument();
expect(button).toBeDisabled();
});
it('should render Spinner when transaction is approved', () => {
useSwapContextMock.mockReturnValue({
to: { loading: false, amount: 1, token: 'ETH' },
from: { loading: false, amount: 1, token: 'BTC' },
lifecycleStatus: { statusName: 'transactionApproved' },
handleSubmit: mockHandleSubmit,
});
render();
const button = screen.getByTestId('ockSwapButton_Button');
expect(screen.getByTestId('spinner')).toBeInTheDocument();
expect(button).toBeDisabled();
});
it('should disable button when required fields are missing', () => {
useSwapContextMock.mockReturnValue({
to: { loading: false, amount: 1, token: 'ETH' },
from: { loading: false, amount: null, token: 'BTC' },
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
render();
const button = screen.getByTestId('ockSwapButton_Button');
expect(button).toBeDisabled();
});
it('should call handleSubmit with mockHandleSubmit when clicked', () => {
useSwapContextMock.mockReturnValue({
address: '0x123',
to: { loading: false, amount: 1, token: { name: 'ETH', address: '123' } },
from: {
loading: false,
amount: 1,
token: { name: 'BTC', address: '456' },
},
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
render();
const button = screen.getByTestId('ockSwapButton_Button');
fireEvent.click(button);
expect(mockHandleSubmit).toHaveBeenCalled();
});
it('should apply additional className correctly', () => {
useSwapContextMock.mockReturnValue({
address: '0x123',
to: { loading: false, amount: 1, token: 'ETH' },
from: { loading: false, amount: 1, token: 'BTC' },
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
const customClass = 'custom-class';
render();
const button = screen.getByTestId('ockSwapButton_Button');
expect(button).toHaveClass(customClass);
});
it('should render ConnectWallet if disconnected and no missing fields', () => {
useSwapContextMock.mockReturnValue({
to: { loading: false, amount: 1, token: 'ETH' },
from: { loading: false, amount: 1, token: 'BTC' },
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
vi.mocked(useAccount).mockReturnValue({
address: '',
status: 'disconnected',
} as unknown as UseAccountReturnType);
vi.mocked(useConnect).mockReturnValue({
connectors: [{ id: 'mockConnector' }],
connect: vi.fn(),
status: 'idle',
} as unknown as UseConnectReturnType);
render();
const button = screen.getByTestId('ockConnectWallet_Container');
expect(button).toBeDefined();
});
it('should handle custom render', async () => {
useSwapContextMock.mockReturnValue({
to: { loading: false, amount: 1, token: 'ETH' },
from: { loading: false, amount: null, token: 'BTC' },
lifecycleStatus: { statusName: 'init' },
handleSubmit: mockHandleSubmit,
});
const swapButton = render(
(
Custom Render
)}
/>,
);
expect(swapButton.queryByText('Custom Render')).toBeInTheDocument();
await act(async () => {
fireEvent.click(swapButton.getByText('Click me'));
});
expect(mockHandleSubmit).toHaveBeenCalled();
});
});