import { useAnalytics } from '@/core/analytics/hooks/useAnalytics';
import { BuyEvent } from '@/core/analytics/types';
import { openPopup } from '@/internal/utils/openPopup';
import { degenToken, ethToken, usdcToken } from '@/token/constants';
import { useOnchainKit } from '@/useOnchainKit';
import { act, fireEvent, render, screen } from '@testing-library/react';
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest';
import { getBuyFundingUrl } from '../utils/getBuyFundingUrl';
import { BuyDropdown } from './BuyDropdown';
import { useBuyContext } from './BuyProvider';
vi.mock('./BuyProvider', () => ({
useBuyContext: vi.fn(),
}));
vi.mock('@/internal/utils/openPopup', () => ({
openPopup: vi.fn(),
}));
vi.mock('@/internal/utils/getRoundedAmount', () => ({
getRoundedAmount: vi.fn(() => '10'),
}));
vi.mock('@/fund/utils/getFundingPopupSize', () => ({
getFundingPopupSize: vi.fn(() => ({ height: 600, width: 400 })),
}));
vi.mock('../utils/getBuyFundingUrl', () => ({
getBuyFundingUrl: vi.fn(() => 'valid-funding-url'),
}));
vi.mock('wagmi', async () => {
const actual = await vi.importActual('wagmi');
return {
...actual,
useAccount: () => ({ address: '0xMockAddress' }),
};
});
vi.mock('@/useOnchainKit', () => ({
useOnchainKit: vi.fn(),
}));
vi.mock('@/core/analytics/hooks/useAnalytics', () => ({
useAnalytics: vi.fn(),
}));
const mockStartPopupMonitor = vi.fn();
const mockContextValue = {
to: {
token: degenToken,
amount: '1.23',
amountUSD: '123.45',
},
fromETH: { token: ethToken },
fromUSDC: { token: usdcToken },
from: { token: { symbol: 'DAI' } },
startPopupMonitor: mockStartPopupMonitor,
setIsDropdownOpen: vi.fn(),
sessionToken: undefined,
};
describe('BuyDropdown', () => {
beforeEach(() => {
vi.clearAllMocks();
(useBuyContext as Mock).mockReturnValue({
...mockContextValue,
fromETH: { token: ethToken, amount: '10' },
fromUSDC: { token: usdcToken, amount: '10' },
from: { token: { symbol: 'DAI' }, amount: '10' },
});
(useOnchainKit as Mock).mockReturnValue({
projectId: 'mock-project-id',
});
(useAnalytics as Mock).mockReturnValue({
sendAnalytics: vi.fn(),
});
});
it('renders the dropdown with correct content', () => {
render();
expect(screen.getByText('Buy with')).toBeInTheDocument();
expect(screen.getByText('10 ETH')).toBeInTheDocument();
expect(screen.getByText('10 USDC')).toBeInTheDocument();
expect(screen.getByText('1.23 DEGEN ≈ $10.00')).toBeInTheDocument();
});
it('triggers handleOnrampClick on payment method click', () => {
(openPopup as Mock).mockReturnValue('popup');
render();
const onrampButton = screen.getByTestId('ock-coinbasePayOnrampItem');
act(() => {
fireEvent.click(onrampButton);
});
expect(mockStartPopupMonitor).toHaveBeenCalled();
});
it('does not render formatted amount if amountUSD is missing', () => {
const contextWithNoUSD = {
...mockContextValue,
to: { ...mockContextValue.to, amountUSD: '0' },
};
(useBuyContext as Mock).mockReturnValue(contextWithNoUSD);
render();
expect(screen.queryByText(/≈/)).not.toBeInTheDocument();
});
it('closes the dropdown when Escape key is pressed', () => {
render();
const { setIsDropdownOpen } = mockContextValue;
act(() => {
fireEvent.keyDown(document, { key: 'Escape' });
});
expect(setIsDropdownOpen).toHaveBeenCalledWith(false);
});
it('sends analytics when a payment method is selected', () => {
const mockSendAnalytics = vi.fn();
(useAnalytics as Mock).mockReturnValue({
sendAnalytics: mockSendAnalytics,
});
(openPopup as Mock).mockReturnValue('popup');
render();
const onrampButton = screen.getByTestId('ock-coinbasePayOnrampItem');
act(() => {
fireEvent.click(onrampButton);
});
expect(mockSendAnalytics).toHaveBeenCalledWith(BuyEvent.BuyOptionSelected, {
option: 'CRYPTO_ACCOUNT',
});
});
it('triggers handleOnrampClick on payment method click', () => {
(openPopup as Mock).mockReturnValue('popup');
(getBuyFundingUrl as Mock).mockReturnValue(undefined);
render();
const onrampButton = screen.getByTestId('ock-coinbasePayOnrampItem');
act(() => {
fireEvent.click(onrampButton);
});
expect(mockStartPopupMonitor).not.toHaveBeenCalled();
});
it('passes sessionToken to getBuyFundingUrl when available', () => {
const sessionToken = 'test-session-token';
(useBuyContext as Mock).mockReturnValue({
...mockContextValue,
sessionToken,
fromETH: { token: ethToken, amount: '10' },
fromUSDC: { token: usdcToken, amount: '10' },
from: { token: { symbol: 'DAI' }, amount: '10' },
});
(openPopup as Mock).mockReturnValue('popup');
(getBuyFundingUrl as Mock).mockReturnValue('valid-funding-url');
render();
const onrampButton = screen.getByTestId('ock-coinbasePayOnrampItem');
act(() => {
fireEvent.click(onrampButton);
});
expect(getBuyFundingUrl).toHaveBeenCalledWith({
to: mockContextValue.to,
paymentMethodId: 'CRYPTO_ACCOUNT',
sessionToken,
});
});
});