Skip to content

Commit

Permalink
Address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
rustam-cb committed Jan 8, 2025
1 parent a1f3b32 commit 0c95bb0
Show file tree
Hide file tree
Showing 6 changed files with 388 additions and 120 deletions.
2 changes: 1 addition & 1 deletion playground/nextjs-app-router/onchainkit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coinbase/onchainkit",
"version": "0.36.1",
"version": "0.36.4",
"type": "module",
"repository": "https://github.com/coinbase/onchainkit.git",
"license": "MIT",
Expand Down
332 changes: 267 additions & 65 deletions src/fund/components/FundCardPaymentMethodDropdown.test.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,320 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import { act } from 'react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { isApplePaySupported } from '@/buy/utils/isApplePaySupported';
import { setOnchainKitConfig } from '@/core/OnchainKitConfig';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest';
import { DEFAULT_PAYMENT_METHODS } from '../constants';
import { FundCardPaymentMethodDropdown } from './FundCardPaymentMethodDropdown';
import { FundCardProvider } from './FundCardProvider';
import { FundCardProvider, useFundContext } from './FundCardProvider';

const renderComponent = () =>
render(
<FundCardProvider asset="BTC">
// Mock the useOutsideClick hook
vi.mock('@/ui-react/internal/hooks/useOutsideClick', () => ({
useOutsideClick: (ref: React.RefObject<HTMLElement>, handler: () => void) => {
// Add click listener to document that calls handler when clicking outside ref
document.addEventListener('mousedown', (event) => {
// If ref or event target is null, return
if (!ref.current || !event.target) {
return;
}

// If click is outside ref element, call handler
if (!ref.current.contains(event.target as Node)) {
handler();
}
});
},
}));

// Mock isApplePaySupported
vi.mock('@/buy/utils/isApplePaySupported', () => ({
isApplePaySupported: vi.fn(),
}));

// Test component to access and modify context
const TestComponent = ({ amount = '5' }: { amount?: string }) => {
const { setFundAmountFiat } = useFundContext();
return (
<>
<button
type="button"
onClick={() => setFundAmountFiat(amount)}
data-testid="setAmount"
>
Set Amount
</button>
<button
type="button"
onClick={() => setFundAmountFiat('1')}
data-testid="setAmount1"
>
Set amount to 1
</button>
<FundCardPaymentMethodDropdown />
</FundCardProvider>,
</>
);
};

describe('FundCardPaymentMethodDropdown', () => {
afterEach(() => {
vi.clearAllMocks();
beforeEach(() => {
vi.resetAllMocks();
setOnchainKitConfig({ apiKey: 'mock-api-key' });

Check failure

Code scanning / CodeQL

Hard-coded credentials Critical

The hard-coded value "mock-api-key" is used as
authorization header
.
The hard-coded value "mock-api-key" is used as
authorization header
.
The hard-coded value "mock-api-key" is used as
authorization header
.
The hard-coded value "mock-api-key" is used as
authorization header
.
(isApplePaySupported as Mock).mockResolvedValue(true); // Default to supported
});

const renderWithProvider = ({ amount = '5' }: { amount?: string }) => {
return render(
<FundCardProvider asset="ETH" paymentMethods={DEFAULT_PAYMENT_METHODS}>
<TestComponent amount={amount} />
</FundCardProvider>,
);
};

it('disables card payment methods when amount is less than minimum', () => {
renderWithProvider({ amount: '1' });

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);

// Check Apple Pay is disabled
const applePayButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectRow__APPLE_PAY',
);
expect(applePayButton).toBeDisabled();
expect(applePayButton).toHaveAttribute(
'title',
'Minimum amount of $5 required',
);

// Check Debit Card is disabled
const debitCardButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectRow__ACH_BANK_ACCOUNT',
);
expect(debitCardButton).toBeDisabled();
expect(debitCardButton).toHaveAttribute(
'title',
'Minimum amount of $5 required',
);

// Check Coinbase is not disabled
const coinbaseButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectRow__FIAT_WALLET',
);
expect(coinbaseButton).not.toBeDisabled();
});

it('renders the first payment method by default', () => {
renderComponent();
it('enables card payment methods when amount meets minimum', () => {
renderWithProvider({ amount: '5' });

// Set amount to 5
fireEvent.click(screen.getByTestId('setAmount'));

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);

// Check all payment methods are enabled
const applePayButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectRow__APPLE_PAY',
);
const debitCardButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectRow__ACH_BANK_ACCOUNT',
);
const coinbaseButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectRow__FIAT_WALLET',
);

expect(applePayButton).not.toBeDisabled();
expect(debitCardButton).not.toBeDisabled();
expect(coinbaseButton).not.toBeDisabled();
});

it('switches to Coinbase when selected method becomes disabled', async () => {
renderWithProvider({ amount: '5' });

// Set amount to 5
fireEvent.click(screen.getByTestId('setAmount'));

// Open dropdown and select Apple Pay
fireEvent.click(
screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle__paymentMethodName',
),
);
fireEvent.click(screen.getByText('Apple Pay'));

// Verify Apple Pay is selected
expect(
screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle__paymentMethodName',
),
).toBeInTheDocument();
).toHaveTextContent('Apple Pay');

// Change amount to below minimum
fireEvent.click(screen.getByTestId('setAmount1'));

// Verify it switched to Coinbase
await waitFor(() => {
expect(
screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle__paymentMethodName',
),
).toHaveTextContent('Coinbase');
});
});

it('toggles the dropdown when the toggle button is clicked', () => {
renderComponent();
const toggleButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle',
it('shows original description when payment method is not disabled', () => {
renderWithProvider({ amount: '5' });

// Set amount to 5
fireEvent.click(screen.getByTestId('setAmount'));

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
// Initially closed

// Check descriptions are original
expect(
screen.queryByTestId('ockFundCardPaymentMethodDropdown'),
).not.toBeInTheDocument();
// Click to open
act(() => {
toggleButton.click();
});
screen.getByText('Buy with your Coinbase account'),
).toBeInTheDocument();

expect(screen.getAllByText('Up to $500/week')).toHaveLength(2);
});

it('closes dropdown when clicking outside', () => {
renderWithProvider({ amount: '5' });

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
expect(
screen.getByTestId('ockFundCardPaymentMethodDropdown'),
).toBeInTheDocument();
// Click to close
act(() => {
toggleButton.click();
});

// Click outside
fireEvent.mouseDown(document.body);

// Verify dropdown is closed
expect(
screen.queryByTestId('ockFundCardPaymentMethodDropdown'),
).not.toBeInTheDocument();
});

it('selects a payment method and updates the selection', () => {
renderComponent();
const toggleButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle',
it('closes dropdown when pressing Escape key', () => {
renderWithProvider({ amount: '5' });

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
act(() => {
toggleButton.click();
});
const applePayOption = screen.getByText('Apple Pay');
act(() => {
applePayOption.click();
});
expect(screen.getByText('Apple Pay')).toBeInTheDocument();
expect(
screen.getByTestId('ockFundCardPaymentMethodDropdown'),
).toBeInTheDocument();

// Press Escape
fireEvent.keyUp(
screen.getByTestId('ockFundCardPaymentMethodDropdownContainer'),
{ key: 'Escape' },
);

// Verify dropdown is closed
expect(
screen.queryByTestId('ockFundCardPaymentMethodDropdown'),
).not.toBeInTheDocument();
});

it('closes the dropdown when clicking outside', () => {
renderComponent();
const toggleButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle',
);
it('toggles dropdown visibility when clicking the toggle button', () => {
renderWithProvider({ amount: '5' });

act(() => {
toggleButton.click();
});
// Initially dropdown should be closed
expect(
screen.queryByTestId('ockFundCardPaymentMethodDropdown'),
).not.toBeInTheDocument();

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
expect(
screen.getByTestId('ockFundCardPaymentMethodDropdown'),
).toBeInTheDocument();

act(() => {
document.body.click();
});

// Close dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
expect(
screen.queryByTestId('ockFundCardPaymentMethodDropdown'),
).not.toBeInTheDocument();
});

it('closes the dropdown when Escape key is pressed', () => {
renderComponent();
const toggleButton = screen.getByTestId(
'ockFundCardPaymentMethodSelectorToggle',
it('ignores non-Escape key presses', () => {
renderWithProvider({ amount: '5' });

// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
expect(
screen.getByTestId('ockFundCardPaymentMethodDropdown'),
).toBeInTheDocument();

act(() => {
toggleButton.click();
});
// Press a different key
fireEvent.keyUp(
screen.getByTestId('ockFundCardPaymentMethodDropdownContainer'),
{ key: 'Enter' },
);

// Verify dropdown is still open
expect(
screen.getByTestId('ockFundCardPaymentMethodDropdown'),
).toBeInTheDocument();
});

act(() => {
fireEvent.keyUp(screen.getByTestId('ockFundCardPaymentMethodDropdown'), {
key: 'Escape',
});
it('hides Apple Pay option when not supported', async () => {
(isApplePaySupported as Mock).mockReturnValue(false);
renderWithProvider({ amount: '5' });

// Wait for Apple Pay check
await waitFor(() => {
// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
});

// Apple Pay should not be in the list
expect(
screen.queryByTestId('ockFundCardPaymentMethodDropdown'),
screen.queryByTestId('ockFundCardPaymentMethodSelectRow__APPLE_PAY'),
).not.toBeInTheDocument();

// Other payment methods should still be there
expect(
screen.getByTestId('ockFundCardPaymentMethodSelectRow__FIAT_WALLET'),
).toBeInTheDocument();
expect(
screen.getByTestId('ockFundCardPaymentMethodSelectRow__ACH_BANK_ACCOUNT'),
).toBeInTheDocument();
});

it('shows Apple Pay option when supported', async () => {
(isApplePaySupported as Mock).mockResolvedValue(true);
renderWithProvider({ amount: '5' });

// Wait for Apple Pay check
await waitFor(() => {
// Open dropdown
fireEvent.click(
screen.getByTestId('ockFundCardPaymentMethodSelectorToggle'),
);
});

// Apple Pay should be in the list
expect(
screen.getByTestId('ockFundCardPaymentMethodSelectRow__APPLE_PAY'),
).toBeInTheDocument();
});
});
Loading

0 comments on commit 0c95bb0

Please sign in to comment.