@reown/appkit-scaffold-ui
Version:
The full stack toolkit to build onchain app UX.
215 lines • 8.82 kB
JavaScript
import { expect, fixture, html } from '@open-wc/testing';
import { afterEach, beforeEach, describe, it, vi } from 'vitest';
import { BlockchainApiController, RouterController, SwapController } from '@reown/appkit-controllers';
import { extendedMainnet, mockChainControllerState } from '@reown/appkit-controllers/testing';
import { W3mSwapSelectTokenView } from '../../src/views/w3m-swap-select-token-view';
const mockToken = {
address: 'eip155:1:0x123',
symbol: 'TEST',
name: 'Test Token',
quantity: {
numeric: '100',
decimals: '18'
},
decimals: 18,
logoUri: 'https://example.com/icon.png',
price: 10,
value: 1000
};
const mockTokens = [
mockToken,
{
...mockToken,
symbol: 'USDT',
name: 'USD Tether',
address: 'eip155:1:0x456'
},
{
...mockToken,
symbol: 'DAI',
name: 'Dai Stablecoin',
address: 'eip155:1:0x789'
}
];
const tokensResponse = {
tokens: [
{
name: 'MATIC',
symbol: 'MATIC',
address: 'eip155:137:0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
decimals: 18,
logoUri: 'https://tokens.1inch.io/0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0.png',
eip2612: false
},
{
name: 'Avalanche Token',
symbol: 'AVAX',
address: 'eip155:137:0x2c89bbc92bd86f8075d1decc58c7f4e0107f286b',
decimals: 18,
logoUri: 'https://tokens.1inch.io/0x2c89bbc92bd86f8075d1decc58c7f4e0107f286b.png',
eip2612: false
},
{
name: 'USD Coin',
symbol: 'USDC',
address: 'eip155:137:0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
decimals: 6,
logoUri: 'https://tokens.1inch.io/0x3c499c542cef5e3811e1192ce70d8cc03d5c3359.png',
eip2612: false
}
]
};
const mockRouterState = {
view: 'SwapSelectToken',
history: ['Connect', 'SwapSelectToken'],
data: {
target: 'sourceToken'
},
transactionStack: []
};
const mockSwapState = {
initializing: false,
initialized: true,
loadingQuote: false,
loadingPrices: false,
loadingTransaction: false,
loadingApprovalTransaction: false,
loadingBuildTransaction: false,
switchingTokens: false,
fetchError: false,
approvalTransaction: undefined,
swapTransaction: undefined,
transactionError: undefined,
sourceToken: mockToken,
sourceTokenAmount: '1',
sourceTokenPriceInUSD: 10,
toToken: { ...mockToken, symbol: 'USDT' },
toTokenAmount: '10',
toTokenPriceInUSD: 1,
networkPrice: '0',
networkBalanceInUSD: '0',
networkTokenSymbol: '',
inputError: undefined,
slippage: 0.5,
tokens: [mockToken],
suggestedTokens: mockTokens,
popularTokens: mockTokens,
foundTokens: undefined,
myTokensWithBalance: mockTokens,
tokensPriceMap: {},
gasFee: '0',
gasPriceInUSD: 2,
priceImpact: undefined,
maxSlippage: undefined,
providerFee: undefined
};
describe('W3mSwapSelectTokenView', () => {
beforeEach(() => {
class MockIntersectionObserver {
constructor(callback) {
this.callback = callback;
this.root = null;
this.rootMargin = '0px';
this.thresholds = [0];
}
observe() {
this.callback([
{
isIntersecting: true,
intersectionRatio: 1,
boundingClientRect: {},
intersectionRect: {},
rootBounds: null,
target: document.createElement('div'),
time: Date.now()
}
], this);
}
unobserve() { }
disconnect() { }
takeRecords() {
return [];
}
}
global.IntersectionObserver = MockIntersectionObserver;
vi.spyOn(SwapController, 'state', 'get').mockReturnValue(mockSwapState);
vi.spyOn(RouterController, 'state', 'get').mockReturnValue(mockRouterState);
vi.spyOn(BlockchainApiController, 'fetchSwapTokens').mockResolvedValue(tokensResponse);
mockChainControllerState({
activeCaipNetwork: extendedMainnet,
activeCaipAddress: 'eip155:1:0x123'
});
SwapController.setBalances(mockTokens);
});
afterEach(() => {
vi.clearAllMocks();
});
it('should render initial state with token lists', async () => {
const element = await fixture(html `<w3m-swap-select-token-view></w3m-swap-select-token-view>`);
await element.updateComplete;
const searchInput = element.shadowRoot?.querySelector('[data-testid="swap-select-token-search-input"]');
expect(searchInput).to.exist;
const suggestedTokens = element.shadowRoot?.querySelectorAll('wui-token-button');
expect(suggestedTokens?.length).to.equal(mockTokens.length);
const yourTokens = element.shadowRoot?.querySelectorAll('wui-token-list-item');
expect(yourTokens?.length).to.equal(mockTokens.length * 2);
});
it('should handle token search', async () => {
const element = await fixture(html `<w3m-swap-select-token-view></w3m-swap-select-token-view>`);
await element.updateComplete;
const searchInput = element.shadowRoot?.querySelector('[data-testid="swap-select-token-search-input"]');
searchInput?.dispatchEvent(new CustomEvent('inputChange', { detail: 'USDT' }));
await element.updateComplete;
const tokenItems = element.shadowRoot?.querySelectorAll('wui-token-list-item');
const visibleTokens = Array.from(tokenItems || []).filter(item => !item.hasAttribute('hidden'));
expect(visibleTokens.length).to.be.greaterThan(0);
visibleTokens.forEach(token => {
expect(token.getAttribute('symbol')?.toLowerCase()).to.include('usdt');
});
});
it('should select source token and go back', async () => {
const setSourceTokenSpy = vi.spyOn(SwapController, 'setSourceToken');
const goBackSpy = vi.spyOn(RouterController, 'goBack');
const element = await fixture(html `<w3m-swap-select-token-view></w3m-swap-select-token-view>`);
await element.updateComplete;
const tokenItem = element.shadowRoot?.querySelector('[data-testid="swap-select-token-item-DAI"]');
tokenItem?.click();
expect(setSourceTokenSpy.mock.calls.length).to.equal(1);
expect(goBackSpy.mock.calls.length).to.equal(1);
});
it('should select destination token and trigger swap', async () => {
vi.spyOn(RouterController, 'state', 'get').mockReturnValue({
...mockRouterState,
data: {
target: 'toToken'
}
});
const setToTokenSpy = vi.spyOn(SwapController, 'setToToken');
const swapTokensSpy = vi.spyOn(SwapController, 'swapTokens');
const goBackSpy = vi.spyOn(RouterController, 'goBack');
const element = await fixture(html `<w3m-swap-select-token-view></w3m-swap-select-token-view>`);
await element.updateComplete;
const tokenItem = element.shadowRoot?.querySelector('[data-testid="swap-select-token-item-DAI"]');
tokenItem?.click();
expect(setToTokenSpy.mock.calls.length).to.equal(1);
expect(swapTokensSpy.mock.calls.length).to.equal(1);
expect(goBackSpy.mock.calls.length).to.equal(1);
});
it('should handle scroll events', async () => {
const element = await fixture(html `<w3m-swap-select-token-view></w3m-swap-select-token-view>`);
await element.updateComplete;
const suggestedTokensContainer = element.shadowRoot?.querySelector('.suggested-tokens-container');
const tokensList = element.shadowRoot?.querySelector('.tokens');
suggestedTokensContainer?.dispatchEvent(new Event('scroll'));
tokensList?.dispatchEvent(new Event('scroll'));
expect(suggestedTokensContainer?.style.getPropertyValue('--suggested-tokens-scroll--left-opacity')).to.exist;
expect(tokensList?.style.getPropertyValue('--tokens-scroll--top-opacity')).to.exist;
});
it('should cleanup event listeners on disconnect', async () => {
const element = await fixture(html `<w3m-swap-select-token-view></w3m-swap-select-token-view>`);
const removeEventListenerSpy = vi.spyOn(HTMLElement.prototype, 'removeEventListener');
element.disconnectedCallback();
expect(removeEventListenerSpy.mock.calls.length).to.equal(2);
});
});
//# sourceMappingURL=w3m-swap-select-token-view.test.js.map