@reown/appkit-pay
Version:
150 lines • 8.95 kB
JavaScript
import { elementUpdated, fixture } from '@open-wc/testing';
import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
import { html } from 'lit';
import { AccountController, ChainController, ConnectionController, ModalController, SnackController } from '@reown/appkit-controllers';
import { PayController } from '../../src/controllers/PayController';
import { W3mPayView } from '../../src/ui/w3m-pay-view';
import { mockConnectionState, mockExchanges, mockPaymentAsset, mockRequestedCaipNetworks } from '../mocks/State';
describe('W3mPayView', () => {
beforeAll(() => {
if (!customElements.get('w3m-pay-view')) {
customElements.define('w3m-pay-view', W3mPayView);
}
});
beforeEach(() => {
PayController.state.isLoading = false;
PayController.state.exchanges = [];
PayController.state.paymentAsset = mockPaymentAsset;
vi.spyOn(AccountController, 'state', 'get').mockReturnValue({
...AccountController.state,
status: 'disconnected',
caipAddress: undefined,
connectedWalletInfo: undefined
});
vi.spyOn(ChainController, 'getAllRequestedCaipNetworks').mockReturnValue(mockRequestedCaipNetworks);
vi.spyOn(PayController, 'fetchExchanges').mockImplementation(async () => {
PayController.state.exchanges = mockExchanges;
});
vi.spyOn(PayController, 'handlePayWithWallet').mockImplementation(() => { });
vi.spyOn(PayController, 'handlePayWithExchange').mockImplementation(async () => null);
vi.spyOn(ConnectionController, 'disconnect').mockImplementation(async () => { });
vi.spyOn(ModalController, 'close').mockImplementation(() => { });
vi.spyOn(SnackController, 'showError').mockImplementation(() => { });
});
test('should render payment header with correct amount and token', async () => {
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const amountText = element.shadowRoot?.querySelector('wui-text[variant="large-700"]');
const tokenText = element.shadowRoot?.querySelector('wui-text[variant="paragraph-600"]');
const networkText = element.shadowRoot?.querySelector('wui-text[variant="small-500"]');
expect(amountText?.textContent).toBe('10000000');
expect(tokenText?.textContent?.trim()).toBe('USDC');
expect(networkText?.textContent?.trim()).toBe('on Ethereum');
});
test('should render disconnected wallet view when not connected', async () => {
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const disconnectedView = element.shadowRoot?.querySelector('[data-testid="wallet-payment-option"]');
expect(disconnectedView).not.toBeNull();
expect(disconnectedView?.querySelector('wui-text')?.textContent).toBe('Pay from wallet');
});
test('should render connected wallet view when connected', async () => {
vi.spyOn(AccountController, 'state', 'get').mockReturnValue({
...AccountController.state,
...mockConnectionState
});
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const connectedView = element.shadowRoot?.querySelector('[data-testid="wallet-payment-option"]');
const disconnectButton = element.shadowRoot?.querySelector('[data-testid="disconnect-button"]');
expect(connectedView).not.toBeNull();
expect(connectedView?.querySelector('wui-text')?.textContent).toBe('Pay with MetaMask');
expect(disconnectButton).not.toBeNull();
});
test('should render loading state when exchanges are loading', async () => {
PayController.state.isLoading = true;
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const spinner = element.shadowRoot?.querySelector('wui-spinner');
expect(spinner).not.toBeNull();
});
test('should render exchanges when available', async () => {
PayController.state.exchanges = mockExchanges;
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const coinbaseOption = element.shadowRoot?.querySelector('[data-testid="exchange-option-coinbase"]');
const binanceOption = element.shadowRoot?.querySelector('[data-testid="exchange-option-binance"]');
expect(coinbaseOption).not.toBeNull();
expect(binanceOption).not.toBeNull();
expect(coinbaseOption?.querySelector('wui-text')?.textContent?.includes('Pay with Coinbase')).toBe(true);
expect(binanceOption?.querySelector('wui-text')?.textContent?.includes('Pay with Binance')).toBe(true);
});
test('should call handlePayWithWallet when wallet payment option is clicked', async () => {
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const walletPaymentOption = element.shadowRoot?.querySelector('[data-testid="wallet-payment-option"]');
await walletPaymentOption?.dispatchEvent(new Event('click'));
expect(PayController.handlePayWithWallet).toHaveBeenCalledOnce();
});
test('should call handlePayWithExchange when an exchange option is clicked', async () => {
PayController.state.exchanges = mockExchanges;
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const coinbaseOption = element.shadowRoot?.querySelector('[data-testid="exchange-option-coinbase"]');
await coinbaseOption?.dispatchEvent(new Event('click'));
expect(PayController.handlePayWithExchange).toHaveBeenCalledWith('coinbase');
});
test('should disconnect wallet when disconnect button is clicked', async () => {
vi.spyOn(AccountController, 'state', 'get').mockReturnValue({
...AccountController.state,
...mockConnectionState
});
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const disconnectButton = element.shadowRoot?.querySelector('[data-testid="disconnect-button"]');
await disconnectButton?.dispatchEvent(new Event('click'));
expect(ConnectionController.disconnect).toHaveBeenCalledOnce();
expect(ModalController.close).toHaveBeenCalledOnce();
});
test('should show error snackbar if disconnection fails', async () => {
vi.spyOn(AccountController, 'state', 'get').mockReturnValue({
...AccountController.state,
...mockConnectionState
});
vi.spyOn(ConnectionController, 'disconnect').mockRejectedValueOnce(new Error('Disconnect failed'));
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const disconnectButton = element.shadowRoot?.querySelector('[data-testid="disconnect-button"]');
await disconnectButton?.dispatchEvent(new Event('click'));
await elementUpdated(element);
expect(SnackController.showError).toHaveBeenCalledWith('Failed to disconnect');
});
test('should show "no exchanges available" when exchanges array is empty', async () => {
PayController.state.exchanges = [];
PayController.state.isLoading = false;
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const noExchangesText = Array.from(element.shadowRoot?.querySelectorAll('wui-text') || []).find(el => el.textContent?.includes('No exchanges available'));
expect(noExchangesText).not.toBeNull();
});
test('should clean up subscriptions when disconnected', async () => {
const unsubscribeSpy = vi.fn();
const subscribeSpy = vi.spyOn(PayController, 'subscribeKey').mockReturnValue(unsubscribeSpy);
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
expect(subscribeSpy).toHaveBeenCalled();
element.remove();
expect(unsubscribeSpy).toHaveBeenCalled();
});
test('should call handlePayment on main button click if wallet connected', async () => {
vi.spyOn(AccountController, 'state', 'get').mockReturnValue({
...AccountController.state,
...mockConnectionState
});
const element = await fixture(html `<w3m-pay-view></w3m-pay-view>`);
await elementUpdated(element);
const connectedView = element.shadowRoot?.querySelector('[data-testid="wallet-payment-option"]');
await connectedView?.dispatchEvent(new Event('click'));
expect(PayController.handlePayWithWallet).toHaveBeenCalledOnce();
});
});
//# sourceMappingURL=w3m-pay-view.test.js.map