mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Add more unit / integration tests for Swaps (#16040)
This commit is contained in:
parent
22f07aefe3
commit
c8067e9351
@ -11,7 +11,7 @@ module.exports = {
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 44,
|
||||
functions: 42,
|
||||
functions: 46.8,
|
||||
lines: 52,
|
||||
statements: 52,
|
||||
},
|
||||
|
@ -120,6 +120,13 @@ export const createSwapsMockStore = () => {
|
||||
},
|
||||
},
|
||||
fromToken: 'ETH',
|
||||
toToken: {
|
||||
symbol: 'USDC',
|
||||
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
||||
occurances: 4,
|
||||
},
|
||||
currentSmartTransactionsErrorMessageDismissed: false,
|
||||
swapsSTXLoading: false,
|
||||
},
|
||||
metamask: {
|
||||
networkDetails: {
|
||||
@ -314,10 +321,10 @@ export const createSwapsMockStore = () => {
|
||||
fetchParams: {
|
||||
metaData: {
|
||||
sourceTokenInfo: {
|
||||
symbol: 'BAT',
|
||||
symbol: 'ETH',
|
||||
},
|
||||
destinationTokenInfo: {
|
||||
symbol: 'ETH',
|
||||
symbol: 'USDC',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -326,6 +333,10 @@ export const createSwapsMockStore = () => {
|
||||
quotesLastFetched: 1519211809934,
|
||||
swapsQuoteRefreshTime: 60000,
|
||||
swapsQuotePrefetchingRefreshTime: 60000,
|
||||
swapsStxBatchStatusRefreshTime: 5000,
|
||||
swapsStxGetTransactionsRefreshTime: 5000,
|
||||
swapsStxMaxFeeMultiplier: 1.5,
|
||||
swapsStxStatusDeadline: 150000,
|
||||
customMaxGas: '',
|
||||
customGasPrice: null,
|
||||
selectedAggId: 'TEST_AGG_2',
|
||||
@ -412,6 +423,7 @@ export const createSwapsMockStore = () => {
|
||||
{
|
||||
uuid: 'uuid2',
|
||||
status: 'success',
|
||||
cancellable: false,
|
||||
statusMetadata: {
|
||||
cancellationFeeWei: 36777567771000,
|
||||
cancellationReason: 'not_cancelled',
|
||||
@ -424,6 +436,7 @@ export const createSwapsMockStore = () => {
|
||||
{
|
||||
uuid: 'uuid2',
|
||||
status: 'pending',
|
||||
cancellable: true,
|
||||
statusMetadata: {
|
||||
cancellationFeeWei: 36777567771000,
|
||||
cancellationReason: 'not_cancelled',
|
||||
|
@ -92,7 +92,7 @@ import {
|
||||
hexWEIToDecGWEI,
|
||||
} from '../../../shared/lib/transactions-controller-utils';
|
||||
|
||||
const GAS_PRICES_LOADING_STATES = {
|
||||
export const GAS_PRICES_LOADING_STATES = {
|
||||
INITIAL: 'INITIAL',
|
||||
LOADING: 'LOADING',
|
||||
FAILED: 'FAILED',
|
||||
|
@ -1,10 +1,14 @@
|
||||
import nock from 'nock';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import { MOCKS, createSwapsMockStore } from '../../../test/jest';
|
||||
import { setSwapsLiveness, setSwapsFeatureFlags } from '../../store/actions';
|
||||
import { CHAIN_IDS } from '../../../shared/constants/network';
|
||||
import { setStorageItem } from '../../../shared/lib/storage-helpers';
|
||||
import * as swaps from './swaps';
|
||||
import swapsReducer, * as swaps from './swaps';
|
||||
|
||||
const middleware = [thunk];
|
||||
|
||||
jest.mock('../../store/actions.js', () => ({
|
||||
setSwapsLiveness: jest.fn(),
|
||||
@ -176,24 +180,6 @@ describe('Ducks - Swaps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomSwapsGas', () => {
|
||||
it('returns "customMaxGas"', () => {
|
||||
const state = createSwapsMockStore();
|
||||
const customMaxGas = '29000';
|
||||
state.metamask.swapsState.customMaxGas = customMaxGas;
|
||||
expect(swaps.getCustomSwapsGas(state)).toBe(customMaxGas);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomMaxFeePerGas', () => {
|
||||
it('returns "customMaxFeePerGas"', () => {
|
||||
const state = createSwapsMockStore();
|
||||
const customMaxFeePerGas = '20';
|
||||
state.metamask.swapsState.customMaxFeePerGas = customMaxFeePerGas;
|
||||
expect(swaps.getCustomMaxFeePerGas(state)).toBe(customMaxFeePerGas);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomMaxPriorityFeePerGas', () => {
|
||||
it('returns "customMaxPriorityFeePerGas"', () => {
|
||||
const state = createSwapsMockStore();
|
||||
@ -206,6 +192,188 @@ describe('Ducks - Swaps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAggregatorMetadata', () => {
|
||||
it('returns agg metadata', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getAggregatorMetadata(state)).toBe(
|
||||
state.swaps.aggregatorMetadata,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBalanceError', () => {
|
||||
it('returns a balance error', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.swaps.balanceError = 'balanceError';
|
||||
expect(swaps.getBalanceError(state)).toBe(state.swaps.balanceError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFromToken', () => {
|
||||
it('returns fromToken', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getFromToken(state)).toBe(state.swaps.fromToken);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFromTokenError', () => {
|
||||
it('returns fromTokenError', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.swaps.fromTokenError = 'fromTokenError';
|
||||
expect(swaps.getFromTokenError(state)).toBe(state.swaps.fromTokenError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFromTokenInputValue', () => {
|
||||
it('returns fromTokenInputValue', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getFromTokenInputValue(state)).toBe(
|
||||
state.swaps.fromTokenInputValue,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIsFeatureFlagLoaded', () => {
|
||||
it('returns isFeatureFlagLoaded', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getIsFeatureFlagLoaded(state)).toBe(
|
||||
state.swaps.isFeatureFlagLoaded,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsSTXLoading', () => {
|
||||
it('returns swapsSTXLoading', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsSTXLoading(state)).toBe(state.swaps.swapsSTXLoading);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMaxSlippage', () => {
|
||||
it('returns maxSlippage', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getMaxSlippage(state)).toBe(state.swaps.maxSlippage);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTopAssets', () => {
|
||||
it('returns topAssets', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getTopAssets(state)).toBe(state.swaps.topAssets);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToToken', () => {
|
||||
it('returns toToken', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getToToken(state)).toBe(state.swaps.toToken);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFetchingQuotes', () => {
|
||||
it('returns fetchingQuotes', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getFetchingQuotes(state)).toBe(state.swaps.fetchingQuotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getQuotesFetchStartTime', () => {
|
||||
it('returns quotesFetchStartTime', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getQuotesFetchStartTime(state)).toBe(
|
||||
state.swaps.quotesFetchStartTime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getReviewSwapClickedTimestamp', () => {
|
||||
it('returns reviewSwapClickedTimestamp', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getReviewSwapClickedTimestamp(state)).toBe(
|
||||
state.swaps.reviewSwapClickedTimestamp,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsCustomizationModalPrice', () => {
|
||||
it('returns customGas.price', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsCustomizationModalPrice(state)).toBe(
|
||||
state.swaps.customGas.price,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsCustomizationModalLimit', () => {
|
||||
it('returns customGas.limit', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsCustomizationModalLimit(state)).toBe(
|
||||
state.swaps.customGas.limit,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapGasPriceEstimateIsLoading', () => {
|
||||
it('returns true for swapGasPriceEstimateIsLoading', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.swaps.customGas.loading = swaps.GAS_PRICES_LOADING_STATES.LOADING;
|
||||
expect(swaps.swapGasPriceEstimateIsLoading(state)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapGasEstimateLoadingHasFailed', () => {
|
||||
it('returns true for swapGasEstimateLoadingHasFailed', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.swaps.customGas.loading = swaps.GAS_PRICES_LOADING_STATES.INITIAL;
|
||||
expect(swaps.swapGasEstimateLoadingHasFailed(state)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapGasPriceEstimateData', () => {
|
||||
it('returns customGas.priceEstimates', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapGasPriceEstimateData(state)).toBe(
|
||||
state.swaps.customGas.priceEstimates,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsFallbackGasPrice', () => {
|
||||
it('returns customGas.fallBackPrice', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsFallbackGasPrice(state)).toBe(
|
||||
state.swaps.customGas.fallBackPrice,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentSmartTransactionsError', () => {
|
||||
it('returns currentSmartTransactionsError', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.swaps.currentSmartTransactionsError =
|
||||
'currentSmartTransactionsError';
|
||||
expect(swaps.getCurrentSmartTransactionsError(state)).toBe(
|
||||
state.swaps.currentSmartTransactionsError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentSmartTransactionsErrorMessageDismissed', () => {
|
||||
it('returns currentSmartTransactionsErrorMessageDismissed', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(
|
||||
swaps.getCurrentSmartTransactionsErrorMessageDismissed(state),
|
||||
).toBe(state.swaps.currentSmartTransactionsErrorMessageDismissed);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldShowCustomPriceTooLowWarning', () => {
|
||||
it('returns false for showCustomPriceTooLowWarning', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.shouldShowCustomPriceTooLowWarning(state)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsFeatureIsLive', () => {
|
||||
it('returns true for "swapsFeatureIsLive"', () => {
|
||||
const state = createSwapsMockStore();
|
||||
@ -222,19 +390,22 @@ describe('Ducks - Swaps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUsedQuote', () => {
|
||||
it('returns selected quote', () => {
|
||||
describe('getSmartTransactionsError', () => {
|
||||
it('returns smartTransactionsError', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getUsedQuote(state)).toMatchObject(
|
||||
state.metamask.swapsState.quotes.TEST_AGG_2,
|
||||
state.appState.smartTransactionsError = 'stxError';
|
||||
expect(swaps.getSmartTransactionsError(state)).toBe(
|
||||
state.appState.smartTransactionsError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns best quote', () => {
|
||||
describe('getSmartTransactionsErrorMessageDismissed', () => {
|
||||
it('returns smartTransactionsErrorMessageDismissed', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.metamask.swapsState.selectedAggId = null;
|
||||
expect(swaps.getUsedQuote(state)).toMatchObject(
|
||||
state.metamask.swapsState.quotes.TEST_AGG_BEST,
|
||||
state.appState.smartTransactionsErrorMessageDismissed = true;
|
||||
expect(swaps.getSmartTransactionsErrorMessageDismissed(state)).toBe(
|
||||
state.appState.smartTransactionsErrorMessageDismissed,
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -288,6 +459,234 @@ describe('Ducks - Swaps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentSmartTransactionsEnabled', () => {
|
||||
it('returns true if STX are enabled and there is no current STX error', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getCurrentSmartTransactionsEnabled(state)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if STX are enabled and there is an current STX error', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.swaps.currentSmartTransactionsError =
|
||||
'currentSmartTransactionsError';
|
||||
expect(swaps.getCurrentSmartTransactionsEnabled(state)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsQuoteRefreshTime', () => {
|
||||
it('returns swapsQuoteRefreshTime', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsQuoteRefreshTime(state)).toBe(
|
||||
state.metamask.swapsState.swapsQuoteRefreshTime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsQuotePrefetchingRefreshTime', () => {
|
||||
it('returns swapsQuotePrefetchingRefreshTime', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsQuotePrefetchingRefreshTime(state)).toBe(
|
||||
state.metamask.swapsState.swapsQuotePrefetchingRefreshTime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBackgroundSwapRouteState', () => {
|
||||
it('returns routeState', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getBackgroundSwapRouteState(state)).toBe(
|
||||
state.metamask.swapsState.routeState,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomSwapsGas', () => {
|
||||
it('returns "customMaxGas"', () => {
|
||||
const state = createSwapsMockStore();
|
||||
const customMaxGas = '29000';
|
||||
state.metamask.swapsState.customMaxGas = customMaxGas;
|
||||
expect(swaps.getCustomSwapsGas(state)).toBe(customMaxGas);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomSwapsGasPrice', () => {
|
||||
it('returns customGasPrice', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getCustomSwapsGasPrice(state)).toBe(
|
||||
state.metamask.swapsState.customGasPrice,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomMaxFeePerGas', () => {
|
||||
it('returns "customMaxFeePerGas"', () => {
|
||||
const state = createSwapsMockStore();
|
||||
const customMaxFeePerGas = '20';
|
||||
state.metamask.swapsState.customMaxFeePerGas = customMaxFeePerGas;
|
||||
expect(swaps.getCustomMaxFeePerGas(state)).toBe(customMaxFeePerGas);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsUserFeeLevel', () => {
|
||||
it('returns swapsUserFeeLevel', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsUserFeeLevel(state)).toBe(
|
||||
state.metamask.swapsState.swapsUserFeeLevel,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFetchParams', () => {
|
||||
it('returns fetchParams', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getFetchParams(state)).toBe(
|
||||
state.metamask.swapsState.fetchParams,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getQuotes', () => {
|
||||
it('returns quotes for Swaps', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getQuotes(state)).toBe(state.metamask.swapsState.quotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getQuotesLastFetched', () => {
|
||||
it('returns quotesLastFetched', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getQuotesLastFetched(state)).toBe(
|
||||
state.metamask.swapsState.quotesLastFetched,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSelectedQuote', () => {
|
||||
it('returns selected quote', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSelectedQuote(state)).toBe(
|
||||
state.metamask.swapsState.quotes.TEST_AGG_2,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsErrorKey', () => {
|
||||
it('returns errorKey', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsErrorKey(state)).toBe(
|
||||
state.metamask.swapsState.errorKey,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getShowQuoteLoadingScreen', () => {
|
||||
it('returns showQuoteLoadingScreen', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getShowQuoteLoadingScreen(state)).toBe(
|
||||
state.swaps.showQuoteLoadingScreen,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsTokens', () => {
|
||||
it('returns tokens', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsTokens(state)).toBe(
|
||||
state.metamask.swapsState.tokens,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsWelcomeMessageSeenStatus', () => {
|
||||
it('returns', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getSwapsWelcomeMessageSeenStatus(state)).toBe(
|
||||
state.metamask.swapsState.swapsWelcomeMessageHasBeenShown,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTopQuote', () => {
|
||||
it('returns a top quote', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getTopQuote(state)).toBe(
|
||||
state.metamask.swapsState.quotes.TEST_AGG_BEST,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getApproveTxId', () => {
|
||||
it('returns approveTxId', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getApproveTxId(state)).toBe(
|
||||
state.metamask.swapsState.approveTxId,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTradeTxId', () => {
|
||||
it('returns tradeTxId', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getTradeTxId(state)).toBe(
|
||||
state.metamask.swapsState.tradeTxId,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUsedQuote', () => {
|
||||
it('returns selected quote', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getUsedQuote(state)).toMatchObject(
|
||||
state.metamask.swapsState.quotes.TEST_AGG_2,
|
||||
);
|
||||
});
|
||||
|
||||
it('returns best quote', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.metamask.swapsState.selectedAggId = null;
|
||||
expect(swaps.getUsedQuote(state)).toMatchObject(
|
||||
state.metamask.swapsState.quotes.TEST_AGG_BEST,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDestinationTokenInfo', () => {
|
||||
it('returns destinationTokenInfo', () => {
|
||||
const state = createSwapsMockStore();
|
||||
expect(swaps.getDestinationTokenInfo(state)).toBe(
|
||||
state.metamask.swapsState.fetchParams.metaData.destinationTokenInfo,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUsedSwapsGasPrice', () => {
|
||||
it('returns customGasPrice', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.metamask.swapsState.customGasPrice = 5;
|
||||
expect(swaps.getUsedSwapsGasPrice(state)).toBe(
|
||||
state.metamask.swapsState.customGasPrice,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getApproveTxParams', () => {
|
||||
it('returns approveTxParams', () => {
|
||||
const state = createSwapsMockStore();
|
||||
state.metamask.swapsState.quotes.TEST_AGG_2.approvalNeeded = {
|
||||
data: '0x095ea7b300000000000000000000000095e6f48254609a6ee006f7d493c8e5fb97094cef0000000000000000000000000000000000000000004a817c7ffffffdabf41c00',
|
||||
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
||||
value: '0x0',
|
||||
from: '0x2369267687A84ac7B494daE2f1542C40E37f4455',
|
||||
gas: '0x12',
|
||||
gasPrice: '0x34',
|
||||
};
|
||||
expect(swaps.getApproveTxParams(state)).toMatchObject({
|
||||
...state.metamask.swapsState.quotes.TEST_AGG_2.approvalNeeded,
|
||||
gasPrice: 5,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSmartTransactionsOptInStatus', () => {
|
||||
it('returns STX opt in status', () => {
|
||||
const state = createSwapsMockStore();
|
||||
@ -325,4 +724,261 @@ describe('Ducks - Swaps', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSmartTransactionEstimatedGas', () => {
|
||||
it('returns unsigned transactions and estimates', () => {
|
||||
const state = createSwapsMockStore();
|
||||
const smartTransactionFees = swaps.getSmartTransactionEstimatedGas(state);
|
||||
expect(smartTransactionFees).toBe(
|
||||
state.metamask.smartTransactionsState.estimatedGas,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSwapsNetworkConfig', () => {
|
||||
it('returns Swaps network config', () => {
|
||||
const state = createSwapsMockStore();
|
||||
const {
|
||||
swapsQuoteRefreshTime,
|
||||
swapsQuotePrefetchingRefreshTime,
|
||||
swapsStxGetTransactionsRefreshTime,
|
||||
swapsStxBatchStatusRefreshTime,
|
||||
swapsStxStatusDeadline,
|
||||
swapsStxMaxFeeMultiplier,
|
||||
} = state.metamask.swapsState;
|
||||
const swapsNetworkConfig = swaps.getSwapsNetworkConfig(state);
|
||||
expect(swapsNetworkConfig).toMatchObject({
|
||||
quoteRefreshTime: swapsQuoteRefreshTime,
|
||||
quotePrefetchingRefreshTime: swapsQuotePrefetchingRefreshTime,
|
||||
stxGetTransactionsRefreshTime: swapsStxGetTransactionsRefreshTime,
|
||||
stxBatchStatusRefreshTime: swapsStxBatchStatusRefreshTime,
|
||||
stxStatusDeadline: swapsStxStatusDeadline,
|
||||
stxMaxFeeMultiplier: swapsStxMaxFeeMultiplier,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions + reducers', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
|
||||
afterEach(() => {
|
||||
store.clearActions();
|
||||
});
|
||||
|
||||
describe('clearSwapsState', () => {
|
||||
it('calls the "swaps/clearSwapsState" action', () => {
|
||||
store.dispatch(swaps.clearSwapsState());
|
||||
const actions = store.getActions();
|
||||
expect(actions).toHaveLength(1);
|
||||
expect(actions[0].type).toBe('swaps/clearSwapsState');
|
||||
});
|
||||
});
|
||||
|
||||
describe('dismissCurrentSmartTransactionsErrorMessage', () => {
|
||||
it('calls the "swaps/dismissCurrentSmartTransactionsErrorMessage" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
store.dispatch(swaps.dismissCurrentSmartTransactionsErrorMessage());
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe(
|
||||
'swaps/dismissCurrentSmartTransactionsErrorMessage',
|
||||
);
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.currentSmartTransactionsErrorMessageDismissed).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAggregatorMetadata', () => {
|
||||
it('calls the "swaps/setAggregatorMetadata" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = {
|
||||
name: 'agg1',
|
||||
};
|
||||
store.dispatch(swaps.setAggregatorMetadata(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setAggregatorMetadata');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.aggregatorMetadata).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setBalanceError', () => {
|
||||
it('calls the "swaps/setBalanceError" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 'balanceError';
|
||||
store.dispatch(swaps.setBalanceError(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setBalanceError');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.balanceError).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setFetchingQuotes', () => {
|
||||
it('calls the "swaps/setFetchingQuotes" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = true;
|
||||
store.dispatch(swaps.setFetchingQuotes(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setFetchingQuotes');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.fetchingQuotes).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSwapsFromToken', () => {
|
||||
it('calls the "swaps/setFromToken" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 'ETH';
|
||||
store.dispatch(swaps.setSwapsFromToken(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setFromToken');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.fromToken).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setFromTokenError', () => {
|
||||
it('calls the "swaps/setFromTokenError" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 'fromTokenError';
|
||||
store.dispatch(swaps.setFromTokenError(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setFromTokenError');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.fromTokenError).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setFromTokenInputValue', () => {
|
||||
it('calls the "swaps/setFromTokenInputValue" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = '5';
|
||||
store.dispatch(swaps.setFromTokenInputValue(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setFromTokenInputValue');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.fromTokenInputValue).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setIsFeatureFlagLoaded', () => {
|
||||
it('calls the "swaps/setIsFeatureFlagLoaded" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = true;
|
||||
store.dispatch(swaps.setIsFeatureFlagLoaded(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setIsFeatureFlagLoaded');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.isFeatureFlagLoaded).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setMaxSlippage', () => {
|
||||
it('calls the "swaps/setMaxSlippage" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 3;
|
||||
store.dispatch(swaps.setMaxSlippage(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setMaxSlippage');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.maxSlippage).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSwapQuotesFetchStartTime', () => {
|
||||
it('calls the "swaps/setQuotesFetchStartTime" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = '1664461886';
|
||||
store.dispatch(swaps.setSwapQuotesFetchStartTime(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setQuotesFetchStartTime');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.quotesFetchStartTime).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setReviewSwapClickedTimestamp', () => {
|
||||
it('calls the "swaps/setReviewSwapClickedTimestamp" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = '1664461886';
|
||||
store.dispatch(swaps.setReviewSwapClickedTimestamp(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setReviewSwapClickedTimestamp');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.reviewSwapClickedTimestamp).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTopAssets', () => {
|
||||
it('calls the "swaps/setTopAssets" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = {
|
||||
'0x514910771af9ca656af840dff83e8264ecf986ca': {
|
||||
index: '0',
|
||||
},
|
||||
'0x04fa0d235c4abf4bcf4787af4cf447de572ef828': {
|
||||
index: '1',
|
||||
},
|
||||
'0x0bc529c00c6401aef6d220be8c6ea1667f6ad93e': {
|
||||
index: '2',
|
||||
},
|
||||
};
|
||||
store.dispatch(swaps.setTopAssets(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setTopAssets');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.topAssets).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSwapToToken', () => {
|
||||
it('calls the "swaps/setToToken" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 'USDC';
|
||||
store.dispatch(swaps.setSwapToToken(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/setToToken');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.toToken).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapCustomGasModalPriceEdited', () => {
|
||||
it('calls the "swaps/swapCustomGasModalPriceEdited" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 5;
|
||||
store.dispatch(swaps.swapCustomGasModalPriceEdited(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/swapCustomGasModalPriceEdited');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.customGas.price).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapCustomGasModalLimitEdited', () => {
|
||||
it('calls the "swaps/swapCustomGasModalLimitEdited" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
const actionPayload = 100;
|
||||
store.dispatch(swaps.swapCustomGasModalLimitEdited(actionPayload));
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/swapCustomGasModalLimitEdited');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.customGas.limit).toBe(actionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapCustomGasModalClosed', () => {
|
||||
it('calls the "swaps/swapCustomGasModalClosed" action', () => {
|
||||
const state = store.getState().swaps;
|
||||
store.dispatch(swaps.swapCustomGasModalClosed());
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toBe('swaps/swapCustomGasModalClosed');
|
||||
const newState = swapsReducer(state, actions[0]);
|
||||
expect(newState.customGas.price).toBe(null);
|
||||
expect(newState.customGas.limit).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ exports[`AwaitingSwap renders the component with initial props 1`] = `
|
||||
<span
|
||||
class="awaiting-swap__amount-and-symbol"
|
||||
>
|
||||
ETH
|
||||
USDC
|
||||
</span>
|
||||
will be added to your account once this transaction has processed.
|
||||
|
||||
|
@ -283,6 +283,7 @@ export default function AwaitingSwap({
|
||||
) : null}
|
||||
<SwapsFooter
|
||||
onSubmit={async () => {
|
||||
/* istanbul ignore next */
|
||||
if (errorKey === OFFLINE_FOR_MAINTENANCE) {
|
||||
await dispatch(prepareToLeaveSwaps());
|
||||
history.push(DEFAULT_ROUTE);
|
||||
|
@ -1,13 +1,26 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
setBackgroundConnection,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import { SLIPPAGE } from '../../../../shared/constants/swaps';
|
||||
import {
|
||||
SLIPPAGE,
|
||||
QUOTES_EXPIRED_ERROR,
|
||||
SWAP_FAILED_ERROR,
|
||||
ERROR_FETCHING_QUOTES,
|
||||
QUOTES_NOT_AVAILABLE_ERROR,
|
||||
CONTRACT_DATA_DISABLED_ERROR,
|
||||
OFFLINE_FOR_MAINTENANCE,
|
||||
} from '../../../../shared/constants/swaps';
|
||||
import AwaitingSwap from '.';
|
||||
|
||||
const middleware = [thunk];
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
swapComplete: false,
|
||||
@ -20,20 +33,25 @@ const createProps = (customProps = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
setBackgroundConnection({
|
||||
stopPollingForQuotes: jest.fn(),
|
||||
});
|
||||
|
||||
describe('AwaitingSwap', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const { getByText } = renderWithProvider(
|
||||
const { getByText, getByTestId } = renderWithProvider(
|
||||
<AwaitingSwap {...createProps()} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Processing')).toBeInTheDocument();
|
||||
expect(getByText('ETH')).toBeInTheDocument();
|
||||
expect(getByText('USDC')).toBeInTheDocument();
|
||||
expect(getByText('View in activity')).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector('.awaiting-swap__main-description'),
|
||||
).toMatchSnapshot();
|
||||
expect(getByText('View in activity')).toBeInTheDocument();
|
||||
expect(getByTestId('page-container-footer-next')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with for completed swap', () => {
|
||||
@ -43,8 +61,110 @@ describe('AwaitingSwap', () => {
|
||||
store,
|
||||
);
|
||||
expect(getByText('Transaction complete')).toBeInTheDocument();
|
||||
expect(getByText('tokens received: ETH')).toBeInTheDocument();
|
||||
expect(getByText('tokens received: USDC')).toBeInTheDocument();
|
||||
expect(getByText('View Swap at etherscan.io')).toBeInTheDocument();
|
||||
expect(getByText('Create a new swap')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with the "OFFLINE_FOR_MAINTENANCE" error', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
errorKey: OFFLINE_FOR_MAINTENANCE,
|
||||
});
|
||||
const { getByText } = renderWithProvider(
|
||||
<AwaitingSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Offline for maintenance')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
'MetaMask Swaps is undergoing maintenance. Please check back later.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with the "SWAP_FAILED_ERROR" error', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
errorKey: SWAP_FAILED_ERROR,
|
||||
});
|
||||
const { getByText } = renderWithProvider(
|
||||
<AwaitingSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Swap failed')).toBeInTheDocument();
|
||||
fireEvent.click(getByText('metamask-flask.zendesk.com'));
|
||||
expect(getByText('Try again')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with the "QUOTES_EXPIRED_ERROR" error', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
errorKey: QUOTES_EXPIRED_ERROR,
|
||||
});
|
||||
const { getByText } = renderWithProvider(
|
||||
<AwaitingSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Quotes timeout')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText('Please request new quotes to get the latest rates.'),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Try again')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with the "ERROR_FETCHING_QUOTES" error', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
errorKey: ERROR_FETCHING_QUOTES,
|
||||
});
|
||||
const { getByText } = renderWithProvider(
|
||||
<AwaitingSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Error fetching quotes')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
'Hmmm... something went wrong. Try again, or if errors persist, contact customer support.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Back')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with the "QUOTES_NOT_AVAILABLE_ERROR" error', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
errorKey: QUOTES_NOT_AVAILABLE_ERROR,
|
||||
});
|
||||
const { getByText } = renderWithProvider(
|
||||
<AwaitingSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('No quotes available')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText('Try adjusting the amount or slippage settings and try again.'),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Try again')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with the "CONTRACT_DATA_DISABLED_ERROR" error', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
errorKey: CONTRACT_DATA_DISABLED_ERROR,
|
||||
});
|
||||
const { getByText } = renderWithProvider(
|
||||
<AwaitingSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(
|
||||
getByText('Contract data is not enabled on your Ledger'),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
'In the Ethereum app on your Ledger, go to "Settings" and allow contract data. Then, try your swap again.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Try again')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -481,6 +481,7 @@ export default function BuildQuote({
|
||||
className="build-quote__token-etherscan-link build-quote__underline"
|
||||
key="build-quote-etherscan-link"
|
||||
onClick={() => {
|
||||
/* istanbul ignore next */
|
||||
trackEvent({
|
||||
event: EVENT_NAMES.EXTERNAL_LINK_CLICKED,
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
@ -678,6 +679,7 @@ export default function BuildQuote({
|
||||
onSelect={onFromSelect}
|
||||
itemsToSearch={tokensToSearchSwapFrom}
|
||||
onInputChange={(value) => {
|
||||
/* istanbul ignore next */
|
||||
onInputChange(value, fromTokenBalance);
|
||||
}}
|
||||
inputValue={fromTokenInputValue}
|
||||
@ -732,6 +734,7 @@ export default function BuildQuote({
|
||||
<div className="build-quote__swap-arrows-row">
|
||||
<button
|
||||
className="build-quote__swap-arrows"
|
||||
data-testid="build-quote__swap-arrows"
|
||||
onClick={() => {
|
||||
onToSelect(selectedFromToken);
|
||||
onFromSelect(selectedToToken);
|
||||
@ -781,6 +784,7 @@ export default function BuildQuote({
|
||||
</div>
|
||||
}
|
||||
primaryAction={
|
||||
/* istanbul ignore next */
|
||||
verificationClicked
|
||||
? null
|
||||
: {
|
||||
@ -809,6 +813,7 @@ export default function BuildQuote({
|
||||
className="build-quote__token-etherscan-link"
|
||||
key="build-quote-etherscan-link"
|
||||
onClick={() => {
|
||||
/* istanbul ignore next */
|
||||
trackEvent({
|
||||
event: 'Clicked Block Explorer Link',
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
@ -861,7 +866,9 @@ export default function BuildQuote({
|
||||
)}
|
||||
</div>
|
||||
<SwapsFooter
|
||||
onSubmit={async () => {
|
||||
onSubmit={
|
||||
/* istanbul ignore next */
|
||||
async () => {
|
||||
// We need this to know how long it took to go from clicking on the Review swap button to rendered View Quote page.
|
||||
dispatch(setReviewSwapClickedTimestamp(Date.now()));
|
||||
// In case that quotes prefetching is waiting to be executed, but hasn't started yet,
|
||||
@ -884,7 +891,8 @@ export default function BuildQuote({
|
||||
await dispatch(setBackgroundSwapRouteState('loading'));
|
||||
history.push(LOADING_QUOTES_ROUTE);
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
submitText={t('swapReviewSwap')}
|
||||
disabled={isReviewSwapButtonDisabled}
|
||||
hideCancel
|
||||
|
@ -6,7 +6,13 @@ import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
setBackgroundConnection,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import {
|
||||
setSwapsFromToken,
|
||||
setSwapToToken,
|
||||
setFromTokenInputValue,
|
||||
} from '../../../ducks/swaps/swaps';
|
||||
import BuildQuote from '.';
|
||||
|
||||
const middleware = [thunk];
|
||||
@ -27,16 +33,46 @@ setBackgroundConnection({
|
||||
clearSwapsQuotes: jest.fn(),
|
||||
stopPollingForQuotes: jest.fn(),
|
||||
clearSmartTransactionFees: jest.fn(),
|
||||
setSwapsFromToken: jest.fn(),
|
||||
setSwapToToken: jest.fn(),
|
||||
setFromTokenInputValue: jest.fn(),
|
||||
});
|
||||
|
||||
jest.mock('../../../ducks/swaps/swaps', () => {
|
||||
const actual = jest.requireActual('../../../ducks/swaps/swaps');
|
||||
return {
|
||||
...actual,
|
||||
setSwapsFromToken: jest.fn(),
|
||||
setSwapToToken: jest.fn(),
|
||||
setFromTokenInputValue: jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_ACTION',
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../swaps.util', () => {
|
||||
const actual = jest.requireActual('../swaps.util');
|
||||
return {
|
||||
...actual,
|
||||
fetchTokenBalance: jest.fn(() => Promise.resolve()),
|
||||
fetchTokenPrice: jest.fn(() => Promise.resolve()),
|
||||
};
|
||||
});
|
||||
|
||||
describe('BuildQuote', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<BuildQuote {...props} />, store);
|
||||
expect(getByText('Swap from')).toBeInTheDocument();
|
||||
expect(getByText('Swap to')).toBeInTheDocument();
|
||||
expect(getByText('ETH')).toBeInTheDocument();
|
||||
expect(getByText('Select')).toBeInTheDocument();
|
||||
expect(getByText('Slippage tolerance')).toBeInTheDocument();
|
||||
expect(getByText('2%')).toBeInTheDocument();
|
||||
expect(getByText('3%')).toBeInTheDocument();
|
||||
@ -45,4 +81,86 @@ describe('BuildQuote', () => {
|
||||
document.querySelector('.slippage-buttons__button-group'),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('switches swap from and to tokens', () => {
|
||||
const setSwapFromTokenMock = jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_ACTION',
|
||||
};
|
||||
});
|
||||
setSwapsFromToken.mockImplementation(setSwapFromTokenMock);
|
||||
const setSwapToTokenMock = jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_ACTION',
|
||||
};
|
||||
});
|
||||
setSwapToToken.mockImplementation(setSwapToTokenMock);
|
||||
const mockStore = createSwapsMockStore();
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const props = createProps();
|
||||
const { getByText, getByTestId } = renderWithProvider(
|
||||
<BuildQuote {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Swap from')).toBeInTheDocument();
|
||||
fireEvent.click(getByTestId('build-quote__swap-arrows'));
|
||||
expect(setSwapsFromToken).toHaveBeenCalledWith(mockStore.swaps.toToken);
|
||||
expect(setSwapToToken).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders the block explorer link, only 1 verified source', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
mockStore.swaps.toToken.occurances = 1;
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<BuildQuote {...props} />, store);
|
||||
expect(getByText('Swap from')).toBeInTheDocument();
|
||||
expect(getByText('Only verified on 1 source.')).toBeInTheDocument();
|
||||
expect(getByText('Etherscan')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the block explorer link, 0 verified sources', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
mockStore.swaps.toToken.occurances = 0;
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<BuildQuote {...props} />, store);
|
||||
expect(getByText('Swap from')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText('This token has been added manually.'),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Etherscan')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicks on a block explorer link', () => {
|
||||
global.platform = { openTab: jest.fn() };
|
||||
const mockStore = createSwapsMockStore();
|
||||
mockStore.swaps.toToken.occurances = 1;
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<BuildQuote {...props} />, store);
|
||||
const blockExplorer = getByText('Etherscan');
|
||||
expect(blockExplorer).toBeInTheDocument();
|
||||
fireEvent.click(blockExplorer);
|
||||
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||
url: 'https://etherscan.io/token/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
||||
});
|
||||
});
|
||||
|
||||
it('clicks on the "max" link', () => {
|
||||
const setFromTokenInputValueMock = jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_ACTION',
|
||||
};
|
||||
});
|
||||
setFromTokenInputValue.mockImplementation(setFromTokenInputValueMock);
|
||||
const mockStore = createSwapsMockStore();
|
||||
mockStore.swaps.fromToken = 'DAI';
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<BuildQuote {...props} />, store);
|
||||
const maxLink = getByText('Max');
|
||||
fireEvent.click(maxLink);
|
||||
expect(setFromTokenInputValue).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -1,12 +1,20 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
fireEvent,
|
||||
setBackgroundConnection,
|
||||
} from '../../../../test/jest';
|
||||
import {
|
||||
setSwapsFromToken,
|
||||
navigateBackToBuildQuote,
|
||||
} from '../../../ducks/swaps/swaps';
|
||||
import CreateNewSwap from '.';
|
||||
|
||||
const middleware = [thunk];
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
sensitiveProperties: {},
|
||||
@ -14,7 +22,28 @@ const createProps = (customProps = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
const backgroundConnection = {
|
||||
navigateBackToBuildQuote: jest.fn(),
|
||||
setBackgroundSwapRouteState: jest.fn(),
|
||||
navigatedBackToBuildQuote: jest.fn(),
|
||||
};
|
||||
|
||||
setBackgroundConnection(backgroundConnection);
|
||||
|
||||
jest.mock('../../../ducks/swaps/swaps', () => {
|
||||
const actual = jest.requireActual('../../../ducks/swaps/swaps');
|
||||
return {
|
||||
...actual,
|
||||
setSwapsFromToken: jest.fn(),
|
||||
navigateBackToBuildQuote: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('CreateNewSwap', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
@ -24,4 +53,28 @@ describe('CreateNewSwap', () => {
|
||||
);
|
||||
expect(getByText('Create a new swap')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicks on the Make another swap link', async () => {
|
||||
const setSwapFromTokenMock = jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_ACTION',
|
||||
};
|
||||
});
|
||||
setSwapsFromToken.mockImplementation(setSwapFromTokenMock);
|
||||
const navigateBackToBuildQuoteMock = jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_ACTION',
|
||||
};
|
||||
});
|
||||
navigateBackToBuildQuote.mockImplementation(navigateBackToBuildQuoteMock);
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(
|
||||
<CreateNewSwap {...props} />,
|
||||
store,
|
||||
);
|
||||
await fireEvent.click(getByText('Create a new swap'));
|
||||
expect(setSwapFromTokenMock).toHaveBeenCalledTimes(1);
|
||||
expect(navigateBackToBuildQuoteMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
@ -4,11 +4,13 @@ import configureMockStore from 'redux-mock-store';
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import DropdownInputPair from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
onInputChange: jest.fn(),
|
||||
...customProps,
|
||||
};
|
||||
};
|
||||
@ -26,4 +28,17 @@ describe('DropdownInputPair', () => {
|
||||
document.querySelector('.dropdown-input-pair__input'),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('changes the input field', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByPlaceholderText } = renderWithProvider(
|
||||
<DropdownInputPair {...props} />,
|
||||
store,
|
||||
);
|
||||
fireEvent.change(getByPlaceholderText('0'), {
|
||||
target: { value: 1.1 },
|
||||
});
|
||||
expect(props.onInputChange).toHaveBeenCalledWith('1.1');
|
||||
});
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ exports[`DropdownSearchList renders the component with initial props 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="dropdown-search-list"
|
||||
data-testid="dropdown-search-list"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
|
@ -91,6 +91,7 @@ export default function DropdownSearchList({
|
||||
setIsImportTokenModalOpen(true);
|
||||
};
|
||||
|
||||
/* istanbul ignore next */
|
||||
const onImportTokenClick = () => {
|
||||
trackEvent({
|
||||
event: 'Token Imported',
|
||||
@ -167,6 +168,7 @@ export default function DropdownSearchList({
|
||||
return (
|
||||
<div
|
||||
className={classnames('dropdown-search-list', className)}
|
||||
data-testid="dropdown-search-list"
|
||||
onClick={onClickSelector}
|
||||
onKeyUp={onKeyUp}
|
||||
tabIndex="0"
|
||||
@ -216,6 +218,7 @@ export default function DropdownSearchList({
|
||||
<SearchableItemList
|
||||
itemsToSearch={loading ? [] : itemsToSearch}
|
||||
Placeholder={() =>
|
||||
/* istanbul ignore next */
|
||||
loading ? (
|
||||
<div className="dropdown-search-list__loading-item">
|
||||
<PulseLoader />
|
||||
@ -286,6 +289,7 @@ export default function DropdownSearchList({
|
||||
/>
|
||||
<div
|
||||
className="dropdown-search-list__close-area"
|
||||
data-testid="dropdown-search-list__close-area"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setIsOpen(false);
|
||||
|
@ -4,6 +4,7 @@ import configureMockStore from 'redux-mock-store';
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import DropdownSearchList from '.';
|
||||
|
||||
@ -17,6 +18,8 @@ const createProps = (customProps = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
jest.mock('../searchable-item-list', () => jest.fn(() => null));
|
||||
|
||||
describe('DropdownSearchList', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
@ -28,4 +31,20 @@ describe('DropdownSearchList', () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(getByText('symbol')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component, opens the list and closes it', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(
|
||||
<DropdownSearchList {...props} />,
|
||||
store,
|
||||
);
|
||||
const dropdownSearchList = getByTestId('dropdown-search-list');
|
||||
expect(dropdownSearchList).toBeInTheDocument();
|
||||
fireEvent.click(dropdownSearchList);
|
||||
const closeButton = getByTestId('dropdown-search-list__close-area');
|
||||
expect(closeButton).toBeInTheDocument();
|
||||
fireEvent.click(closeButton);
|
||||
expect(closeButton).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ exports[`ExchangeRateDisplay renders the component with initial props 1`] = `
|
||||
</span>
|
||||
<span
|
||||
class="exchange-rate-display__bold"
|
||||
data-testid="exchange-rate-display__base-symbol"
|
||||
>
|
||||
ETH
|
||||
</span>
|
||||
@ -26,6 +27,7 @@ exports[`ExchangeRateDisplay renders the component with initial props 1`] = `
|
||||
</span>
|
||||
<div
|
||||
class="exchange-rate-display__switch-arrows"
|
||||
data-testid="exchange-rate-display__switch-arrows"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
|
@ -66,6 +66,7 @@ export default function ExchangeRateDisplay({
|
||||
<span>1</span>
|
||||
<span
|
||||
className={classnames({ 'exchange-rate-display__bold': boldSymbols })}
|
||||
data-testid="exchange-rate-display__base-symbol"
|
||||
>
|
||||
{baseSymbol}
|
||||
</span>
|
||||
@ -80,6 +81,7 @@ export default function ExchangeRateDisplay({
|
||||
className={classnames('exchange-rate-display__switch-arrows', {
|
||||
'exchange-rate-display__switch-arrows-rotate': rotating,
|
||||
})}
|
||||
data-testid="exchange-rate-display__switch-arrows"
|
||||
onClick={() => {
|
||||
setShowPrimaryToSecondary(!showPrimaryToSecondary);
|
||||
setRotating(true);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider } from '../../../../test/jest';
|
||||
import { renderWithProvider, fireEvent } from '../../../../test/jest';
|
||||
import ExchangeRateDisplay from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
@ -25,4 +25,18 @@ describe('ExchangeRateDisplay', () => {
|
||||
expect(getByText(props.secondaryTokenSymbol)).toBeInTheDocument();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('clicks on the switch link', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(
|
||||
<ExchangeRateDisplay {...props} />,
|
||||
);
|
||||
expect(getByTestId('exchange-rate-display__base-symbol')).toHaveTextContent(
|
||||
'ETH',
|
||||
);
|
||||
fireEvent.click(getByTestId('exchange-rate-display__switch-arrows'));
|
||||
expect(getByTestId('exchange-rate-display__base-symbol')).toHaveTextContent(
|
||||
'BAT',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -3,3 +3,32 @@
|
||||
exports[`FeeCard renders the component with EIP-1559 enabled 1`] = `null`;
|
||||
|
||||
exports[`FeeCard renders the component with initial props 1`] = `null`;
|
||||
|
||||
exports[`FeeCard renders the component with initial props 2`] = `
|
||||
<div
|
||||
class="info-tooltip"
|
||||
>
|
||||
<div
|
||||
class="fee-card__row-label fee-card__info-tooltip-container"
|
||||
>
|
||||
<div
|
||||
aria-describedby="tippy-tooltip-1"
|
||||
class="info-tooltip__tooltip-container fee-card__info-tooltip-content-container"
|
||||
data-original-title="null"
|
||||
data-tooltipped=""
|
||||
style="display: inline;"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 10 10"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5 0C2.2 0 0 2.2 0 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 2c.4 0 .7.3.7.7s-.3.7-.7.7-.7-.2-.7-.6.3-.8.7-.8zm.7 6H4.3V4.3h1.5V8z"
|
||||
fill="var(--color-icon-alternative)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -31,6 +31,7 @@ export default function FeeCard({
|
||||
}) {
|
||||
const t = useContext(I18nContext);
|
||||
|
||||
/* istanbul ignore next */
|
||||
const getTranslatedNetworkName = () => {
|
||||
switch (chainId) {
|
||||
case CHAIN_IDS.MAINNET:
|
||||
@ -84,6 +85,7 @@ export default function FeeCard({
|
||||
<a
|
||||
className="fee-card__link"
|
||||
onClick={() => {
|
||||
/* istanbul ignore next */
|
||||
trackEvent({
|
||||
event: 'Clicked "Gas Fees: Learn More" Link',
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
createSwapsMockStore,
|
||||
setBackgroundConnection,
|
||||
MOCKS,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import { CHAIN_IDS } from '../../../../shared/constants/network';
|
||||
|
||||
@ -104,6 +105,8 @@ describe('FeeCard', () => {
|
||||
expect(
|
||||
document.querySelector('.fee-card__top-bordered-row'),
|
||||
).toMatchSnapshot();
|
||||
expect(document.querySelector('.info-tooltip')).toMatchSnapshot();
|
||||
expect(getByText('Edit limit')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with EIP-1559 enabled', () => {
|
||||
@ -145,4 +148,23 @@ describe('FeeCard', () => {
|
||||
expect(getByText(`: ${props.secondaryFee.maxFee}`)).toBeInTheDocument();
|
||||
expect(queryByTestId('fee-card__edit-link')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the component with hidden token approval row', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
hideTokenApprovalRow: true,
|
||||
});
|
||||
const { queryByText } = renderWithProvider(<FeeCard {...props} />, store);
|
||||
expect(queryByText('Edit limit')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('approves a token', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
onTokenApprovalClick: jest.fn(),
|
||||
});
|
||||
const { queryByText } = renderWithProvider(<FeeCard {...props} />, store);
|
||||
fireEvent.click(queryByText('Edit limit'));
|
||||
expect(props.onTokenApprovalClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -77,6 +77,7 @@ exports[`MainQuoteSummary renders the component with initial props 4`] = `
|
||||
</span>
|
||||
<span
|
||||
class=""
|
||||
data-testid="exchange-rate-display__base-symbol"
|
||||
>
|
||||
ETH
|
||||
</span>
|
||||
@ -93,6 +94,7 @@ exports[`MainQuoteSummary renders the component with initial props 4`] = `
|
||||
</span>
|
||||
<div
|
||||
class="exchange-rate-display__switch-arrows"
|
||||
data-testid="exchange-rate-display__switch-arrows"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
|
@ -39,6 +39,7 @@ exports[`SearchableItemList renders the component with initial props 1`] = `
|
||||
exports[`SearchableItemList renders the component with initial props 2`] = `
|
||||
<div
|
||||
class="searchable-item-list__item searchable-item-list__item--selected"
|
||||
data-testid="searchable-item-list__item"
|
||||
tabindex="0"
|
||||
>
|
||||
<img
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ItemList renders the component with initial props 1`] = `
|
||||
<div
|
||||
class="searchable-item-list__item searchable-item-list__item--selected"
|
||||
data-testid="searchable-item-list__item"
|
||||
tabindex="0"
|
||||
>
|
||||
<img
|
||||
alt="primaryLabel"
|
||||
class="url-icon"
|
||||
src="iconUrl"
|
||||
/>
|
||||
<div
|
||||
class="searchable-item-list__labels"
|
||||
>
|
||||
<div
|
||||
class="searchable-item-list__item-labels"
|
||||
>
|
||||
<span
|
||||
class="searchable-item-list__primary-label"
|
||||
>
|
||||
primaryLabel
|
||||
</span>
|
||||
<span
|
||||
class="searchable-item-list__secondary-label"
|
||||
>
|
||||
secondaryLabel
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="searchable-item-list__right-labels"
|
||||
>
|
||||
<span
|
||||
class="searchable-item-list__right-primary-label"
|
||||
>
|
||||
rightPrimaryLabel
|
||||
</span>
|
||||
<span
|
||||
class="searchable-item-list__right-secondary-label"
|
||||
>
|
||||
rightSecondaryLabel
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -89,6 +89,7 @@ export default function ItemList({
|
||||
'searchable-item-list__item--selected': selected,
|
||||
'searchable-item-list__item--disabled': disabled,
|
||||
})}
|
||||
data-testid="searchable-item-list__item"
|
||||
onClick={onClick}
|
||||
onKeyUp={(e) => e.key === 'Enter' && onClick()}
|
||||
key={`searchable-item-list-item-${i}`}
|
||||
@ -150,6 +151,7 @@ export default function ItemList({
|
||||
<a
|
||||
key="searchable-item-list__etherscan-link"
|
||||
onClick={() => {
|
||||
/* istanbul ignore next */
|
||||
trackEvent({
|
||||
event: 'Clicked Block Explorer Link',
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
|
@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
fireEvent,
|
||||
} from '../../../../../test/jest';
|
||||
import ItemList from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
defaultToAll: true,
|
||||
listTitle: 'listTitle',
|
||||
onClickItem: jest.fn(),
|
||||
results: [
|
||||
{
|
||||
iconUrl: 'iconUrl',
|
||||
selected: true,
|
||||
primaryLabel: 'primaryLabel',
|
||||
secondaryLabel: 'secondaryLabel',
|
||||
rightPrimaryLabel: 'rightPrimaryLabel',
|
||||
rightSecondaryLabel: 'rightSecondaryLabel',
|
||||
},
|
||||
],
|
||||
fuseSearchKeys: [
|
||||
{
|
||||
name: 'name',
|
||||
weight: 0.499,
|
||||
},
|
||||
{
|
||||
name: 'symbol',
|
||||
weight: 0.499,
|
||||
},
|
||||
{
|
||||
name: 'address',
|
||||
weight: 0.002,
|
||||
},
|
||||
],
|
||||
...customProps,
|
||||
};
|
||||
};
|
||||
|
||||
describe('ItemList', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<ItemList {...props} />, store);
|
||||
expect(getByText(props.listTitle)).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector('.searchable-item-list__item'),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('clicks on a list item', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByText, getByTestId } = renderWithProvider(
|
||||
<ItemList {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText(props.listTitle)).toBeInTheDocument();
|
||||
fireEvent.click(getByTestId('searchable-item-list__item'));
|
||||
expect(props.onClickItem).toHaveBeenCalledWith(props.results[0]);
|
||||
});
|
||||
|
||||
it('presses the "Enter" key on a list item', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByText, getByTestId } = renderWithProvider(
|
||||
<ItemList {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText(props.listTitle)).toBeInTheDocument();
|
||||
fireEvent.keyUp(getByTestId('searchable-item-list__item'), {
|
||||
key: 'Enter',
|
||||
code: 'Enter',
|
||||
charCode: 13,
|
||||
});
|
||||
expect(props.onClickItem).toHaveBeenCalledWith(props.results[0]);
|
||||
});
|
||||
});
|
@ -0,0 +1,107 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
fireEvent,
|
||||
} from '../../../../../test/jest';
|
||||
import ListItemSearch from './list-item-search.component';
|
||||
|
||||
const token = {
|
||||
erc20: true,
|
||||
symbol: 'BAT',
|
||||
decimals: 18,
|
||||
address: '0x0D8775F648430679A709E98d2b0Cb6250d2887EF',
|
||||
};
|
||||
|
||||
jest.mock('../../swaps.util', () => {
|
||||
const original = jest.requireActual('../../swaps.util');
|
||||
return {
|
||||
...original,
|
||||
fetchToken: jest.fn(() => {
|
||||
return token;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
onSearch: jest.fn(),
|
||||
setSearchQuery: jest.fn(),
|
||||
listToSearch: [
|
||||
{
|
||||
iconUrl: 'iconUrl',
|
||||
selected: true,
|
||||
primaryLabel: 'primaryLabel',
|
||||
secondaryLabel: 'secondaryLabel',
|
||||
rightPrimaryLabel: 'rightPrimaryLabel',
|
||||
rightSecondaryLabel: 'rightSecondaryLabel',
|
||||
},
|
||||
],
|
||||
fuseSearchKeys: [
|
||||
{
|
||||
name: 'name',
|
||||
weight: 0.499,
|
||||
},
|
||||
{
|
||||
name: 'symbol',
|
||||
weight: 0.499,
|
||||
},
|
||||
{
|
||||
name: 'address',
|
||||
weight: 0.002,
|
||||
},
|
||||
],
|
||||
searchPlaceholderText: 'Search token',
|
||||
defaultToAll: true,
|
||||
...customProps,
|
||||
};
|
||||
};
|
||||
|
||||
const middleware = [thunk];
|
||||
|
||||
describe('ListItemSearch', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(
|
||||
<ListItemSearch {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByTestId('search-list-items')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('changes the search query', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(
|
||||
<ListItemSearch {...props} />,
|
||||
store,
|
||||
);
|
||||
const input = getByTestId('search-list-items');
|
||||
fireEvent.change(input, { target: { value: 'USD' } });
|
||||
expect(props.setSearchQuery).toHaveBeenCalledWith('USD');
|
||||
expect(props.onSearch).toHaveBeenCalledWith({
|
||||
searchQuery: 'USD',
|
||||
results: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('imports a token', async () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({ shouldSearchForImports: true });
|
||||
const { getByTestId } = renderWithProvider(
|
||||
<ListItemSearch {...props} />,
|
||||
store,
|
||||
);
|
||||
const input = getByTestId('search-list-items');
|
||||
await fireEvent.change(input, { target: { value: token.address } });
|
||||
expect(props.setSearchQuery).toHaveBeenCalledWith(token.address);
|
||||
expect(props.onSearch).toHaveBeenCalledWith({
|
||||
searchQuery: token.address,
|
||||
results: [token],
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
} from '../../../../../test/jest';
|
||||
import quoteDataRows from '../mock-quote-data';
|
||||
import QuoteDetails from './quote-details';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
...quoteDataRows[0],
|
||||
slippage: 2,
|
||||
liquiditySourceKey: 'swapAggregator',
|
||||
minimumAmountReceived: '2',
|
||||
feeInEth: '0.0003',
|
||||
metaMaskFee: 0.0205,
|
||||
...customProps,
|
||||
};
|
||||
};
|
||||
|
||||
describe('ListItemSearch', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(
|
||||
<QuoteDetails {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Rate')).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -3,6 +3,7 @@
|
||||
exports[`SortList renders the component with initial props 1`] = `
|
||||
<div
|
||||
class="select-quote-popover__column-header select-quote-popover__receiving"
|
||||
data-testid="select-quote-popover__receiving"
|
||||
>
|
||||
<span
|
||||
class="select-quote-popover__receiving-symbol"
|
||||
@ -50,6 +51,7 @@ exports[`SortList renders the component with initial props 1`] = `
|
||||
exports[`SortList renders the component with initial props 2`] = `
|
||||
<div
|
||||
class="select-quote-popover__column-header select-quote-popover__network-fees select-quote-popover__network-fees-header"
|
||||
data-testid="select-quote-popover__network-fees-header"
|
||||
>
|
||||
<span>
|
||||
Estimated network fees
|
||||
@ -88,6 +90,7 @@ exports[`SortList renders the component with initial props 2`] = `
|
||||
exports[`SortList renders the component with initial props 3`] = `
|
||||
<div
|
||||
class="select-quote-popover__row select-quote-popover__row--selected"
|
||||
data-testid="select-quote-popover-row-1"
|
||||
>
|
||||
<div
|
||||
class="select-quote-popover__receiving"
|
||||
@ -124,6 +127,7 @@ exports[`SortList renders the component with initial props 3`] = `
|
||||
</div>
|
||||
<div
|
||||
class="select-quote-popover__caret-right"
|
||||
data-testid="select-quote-popover__caret-right-1"
|
||||
>
|
||||
<i
|
||||
class="fa fa-angle-up"
|
||||
|
@ -80,6 +80,7 @@ export default function SortList({
|
||||
<div className="select-quote-popover__column-headers">
|
||||
<div
|
||||
className="select-quote-popover__column-header select-quote-popover__receiving"
|
||||
data-testid="select-quote-popover__receiving"
|
||||
onClick={() => onColumnHeaderClick('destinationTokenValue')}
|
||||
>
|
||||
<span className="select-quote-popover__receiving-symbol">
|
||||
@ -96,6 +97,7 @@ export default function SortList({
|
||||
</div>
|
||||
<div
|
||||
className="select-quote-popover__column-header select-quote-popover__network-fees select-quote-popover__network-fees-header"
|
||||
data-testid="select-quote-popover__network-fees-header"
|
||||
onClick={() => onColumnHeaderClick('rawNetworkFees')}
|
||||
>
|
||||
{!hideEstimatedGasFee && (
|
||||
@ -111,6 +113,7 @@ export default function SortList({
|
||||
</div>
|
||||
<div
|
||||
className="select-quote-popover__column-header select-quote-popover__quote-source"
|
||||
data-testid="select-quote-popover__quote-source"
|
||||
onClick={() => onColumnHeaderClick('quoteSource')}
|
||||
>
|
||||
{t('swapQuoteSource')}
|
||||
@ -137,6 +140,7 @@ export default function SortList({
|
||||
})}
|
||||
onClick={() => onSelect(aggId)}
|
||||
key={`select-quote-popover-row-${i}`}
|
||||
data-testid={`select-quote-popover-row-${i}`}
|
||||
>
|
||||
<div className="select-quote-popover__receiving">
|
||||
<div className="select-quote-popover__receiving-value">
|
||||
@ -178,6 +182,7 @@ export default function SortList({
|
||||
</div>
|
||||
<div
|
||||
className="select-quote-popover__caret-right"
|
||||
data-testid={`select-quote-popover__caret-right-${i}`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onCaretClick(aggId);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider } from '../../../../../test/jest';
|
||||
import { renderWithProvider, fireEvent } from '../../../../../test/jest';
|
||||
import SortList from './sort-list';
|
||||
|
||||
jest.mock(
|
||||
@ -86,4 +86,32 @@ describe('SortList', () => {
|
||||
document.querySelector('.select-quote-popover__row--selected'),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('clicks on the "destinationTokenValue" header', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
fireEvent.click(getByTestId('select-quote-popover__receiving'));
|
||||
expect(props.setSortColumn).toHaveBeenCalledWith('destinationTokenValue');
|
||||
});
|
||||
|
||||
it('clicks on the "rawNetworkFees" header', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
fireEvent.click(getByTestId('select-quote-popover__network-fees-header'));
|
||||
expect(props.setSortColumn).toHaveBeenCalledWith('rawNetworkFees');
|
||||
});
|
||||
|
||||
it('clicks on the first aggregator', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
fireEvent.click(getByTestId('select-quote-popover-row-0'));
|
||||
expect(props.onSelect).toHaveBeenCalledWith('Agg1');
|
||||
});
|
||||
|
||||
it('clicks on a caret for the first aggregator', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
fireEvent.click(getByTestId('select-quote-popover__caret-right-0'));
|
||||
expect(props.onCaretClick).toHaveBeenCalledWith('Agg1');
|
||||
});
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ exports[`SlippageButtons renders the component with initial props 2`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`SlippageButtons renders the component with the smart transaction opt-in button available 1`] = `
|
||||
exports[`SlippageButtons renders the component with the smart transaction opt-in button available, opt into STX 1`] = `
|
||||
<button
|
||||
class="slippage-buttons__header slippage-buttons__header--open"
|
||||
>
|
||||
@ -62,7 +62,7 @@ exports[`SlippageButtons renders the component with the smart transaction opt-in
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`SlippageButtons renders the component with the smart transaction opt-in button available 2`] = `
|
||||
exports[`SlippageButtons renders the component with the smart transaction opt-in button available, opt into STX 2`] = `
|
||||
<div
|
||||
class="button-group slippage-buttons__button-group radio-button-group"
|
||||
role="radiogroup"
|
||||
|
@ -170,6 +170,7 @@ export default function SlippageButtons({
|
||||
)}
|
||||
>
|
||||
<input
|
||||
data-testid="slippage-buttons__custom-slippage"
|
||||
onChange={(event) => {
|
||||
const { value } = event.target;
|
||||
const isValueNumeric = !isNaN(Number(value));
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider } from '../../../../test/jest';
|
||||
import { renderWithProvider, fireEvent } from '../../../../test/jest';
|
||||
import { SLIPPAGE } from '../../../../shared/constants/swaps';
|
||||
import SlippageButtons from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
onSelect: jest.fn(),
|
||||
maxAllowedSlippage: 15,
|
||||
currentSlippage: 3,
|
||||
currentSlippage: SLIPPAGE.HIGH,
|
||||
smartTransactionsEnabled: false,
|
||||
...customProps,
|
||||
};
|
||||
@ -15,7 +16,7 @@ const createProps = (customProps = {}) => {
|
||||
|
||||
describe('SlippageButtons', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const { getByText, queryByText } = renderWithProvider(
|
||||
const { getByText, queryByText, getByTestId } = renderWithProvider(
|
||||
<SlippageButtons {...createProps()} />,
|
||||
);
|
||||
expect(getByText('2%')).toBeInTheDocument();
|
||||
@ -29,11 +30,21 @@ describe('SlippageButtons', () => {
|
||||
document.querySelector('.slippage-buttons__button-group'),
|
||||
).toMatchSnapshot();
|
||||
expect(queryByText('Smart transaction')).not.toBeInTheDocument();
|
||||
expect(getByTestId('button-group__button1')).toHaveAttribute(
|
||||
'aria-checked',
|
||||
'true',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders the component with the smart transaction opt-in button available', () => {
|
||||
it('renders the component with the smart transaction opt-in button available, opt into STX', () => {
|
||||
const setSmartTransactionsOptInStatus = jest.fn();
|
||||
const { getByText } = renderWithProvider(
|
||||
<SlippageButtons {...createProps({ smartTransactionsEnabled: true })} />,
|
||||
<SlippageButtons
|
||||
{...createProps({
|
||||
smartTransactionsEnabled: true,
|
||||
setSmartTransactionsOptInStatus,
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
expect(getByText('2%')).toBeInTheDocument();
|
||||
expect(getByText('3%')).toBeInTheDocument();
|
||||
@ -46,5 +57,69 @@ describe('SlippageButtons', () => {
|
||||
document.querySelector('.slippage-buttons__button-group'),
|
||||
).toMatchSnapshot();
|
||||
expect(getByText('Smart transaction')).toBeInTheDocument();
|
||||
expect(document.querySelector('.toggle-button--off')).toBeInTheDocument();
|
||||
fireEvent.click(document.querySelector('.toggle-button'));
|
||||
expect(setSmartTransactionsOptInStatus).toHaveBeenCalledWith(true, false);
|
||||
});
|
||||
|
||||
it('renders slippage with a custom value', () => {
|
||||
const { getByText } = renderWithProvider(
|
||||
<SlippageButtons {...createProps({ currentSlippage: 2.5 })} />,
|
||||
);
|
||||
expect(getByText('2.5')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the default slippage with Advanced options hidden', () => {
|
||||
const { getByText, queryByText } = renderWithProvider(
|
||||
<SlippageButtons
|
||||
{...createProps({ currentSlippage: SLIPPAGE.DEFAULT })}
|
||||
/>,
|
||||
);
|
||||
expect(getByText('Advanced options')).toBeInTheDocument();
|
||||
expect(document.querySelector('.fa-angle-down')).toBeInTheDocument();
|
||||
expect(queryByText('2%')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens the Advanced options section and sets a default slippage', () => {
|
||||
const { getByText, getByTestId } = renderWithProvider(
|
||||
<SlippageButtons
|
||||
{...createProps({ currentSlippage: SLIPPAGE.DEFAULT })}
|
||||
/>,
|
||||
);
|
||||
fireEvent.click(getByText('Advanced options'));
|
||||
fireEvent.click(getByTestId('button-group__button0'));
|
||||
expect(getByTestId('button-group__button0')).toHaveAttribute(
|
||||
'aria-checked',
|
||||
'true',
|
||||
);
|
||||
});
|
||||
|
||||
it('opens the Advanced options section and sets a high slippage', () => {
|
||||
const { getByText, getByTestId } = renderWithProvider(
|
||||
<SlippageButtons
|
||||
{...createProps({ currentSlippage: SLIPPAGE.DEFAULT })}
|
||||
/>,
|
||||
);
|
||||
fireEvent.click(getByText('Advanced options'));
|
||||
fireEvent.click(getByTestId('button-group__button1'));
|
||||
expect(getByTestId('button-group__button1')).toHaveAttribute(
|
||||
'aria-checked',
|
||||
'true',
|
||||
);
|
||||
});
|
||||
|
||||
it('sets a custom slippage value', () => {
|
||||
const { getByTestId } = renderWithProvider(
|
||||
<SlippageButtons {...createProps()} />,
|
||||
);
|
||||
fireEvent.click(getByTestId('button-group__button2'));
|
||||
expect(getByTestId('button-group__button2')).toHaveAttribute(
|
||||
'aria-checked',
|
||||
'true',
|
||||
);
|
||||
const input = getByTestId('slippage-buttons__custom-slippage');
|
||||
fireEvent.change(input, { target: { value: 5 } });
|
||||
fireEvent.click(document);
|
||||
expect(input).toHaveAttribute('value', '5');
|
||||
});
|
||||
});
|
||||
|
@ -6,7 +6,9 @@ import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
setBackgroundConnection,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import { CHAIN_IDS } from '../../../../shared/constants/network';
|
||||
import SmartTransactionStatus from '.';
|
||||
|
||||
const middleware = [thunk];
|
||||
@ -15,6 +17,28 @@ setBackgroundConnection({
|
||||
setBackgroundSwapRouteState: jest.fn(),
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => {
|
||||
const original = jest.requireActual('react-router-dom');
|
||||
return {
|
||||
...original,
|
||||
useHistory: () => ({
|
||||
push: jest.fn(),
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../ducks/swaps/swaps', () => {
|
||||
const original = jest.requireActual('../../../ducks/swaps/swaps');
|
||||
return {
|
||||
...original,
|
||||
prepareToLeaveSwaps: jest.fn(() => {
|
||||
return {
|
||||
type: 'MOCK_TYPE',
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
describe('SmartTransactionStatus', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
@ -22,4 +46,109 @@ describe('SmartTransactionStatus', () => {
|
||||
expect(getByText('Publicly submitting your Swap...')).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the "success" STX status', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
const latestSmartTransaction =
|
||||
mockStore.metamask.smartTransactionsState.smartTransactions[
|
||||
CHAIN_IDS.MAINNET
|
||||
][1];
|
||||
latestSmartTransaction.status = 'success';
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Swap complete!')).toBeInTheDocument();
|
||||
expect(getByText('Your USDC is now available.')).toBeInTheDocument();
|
||||
expect(getByText('Create a new swap')).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the "reverted" STX status', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
const latestSmartTransaction =
|
||||
mockStore.metamask.smartTransactionsState.smartTransactions[
|
||||
CHAIN_IDS.MAINNET
|
||||
][1];
|
||||
latestSmartTransaction.status = 'reverted';
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Swap failed')).toBeInTheDocument();
|
||||
expect(getByText('customer support')).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the "cancelled_user_cancelled" STX status', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
const latestSmartTransaction =
|
||||
mockStore.metamask.smartTransactionsState.smartTransactions[
|
||||
CHAIN_IDS.MAINNET
|
||||
][1];
|
||||
latestSmartTransaction.status = 'cancelled_user_cancelled';
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Swap cancelled')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
'Your transaction has been cancelled and you did not pay any unnecessary gas fees.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the "deadline_missed" STX status', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
const latestSmartTransaction =
|
||||
mockStore.metamask.smartTransactionsState.smartTransactions[
|
||||
CHAIN_IDS.MAINNET
|
||||
][1];
|
||||
latestSmartTransaction.status = 'deadline_missed';
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Swap would have failed')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
'Your transaction would have failed and was cancelled to protect you from paying unnecessary gas fees.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the "unknown" STX status', () => {
|
||||
const mockStore = createSwapsMockStore();
|
||||
const latestSmartTransaction =
|
||||
mockStore.metamask.smartTransactionsState.smartTransactions[
|
||||
CHAIN_IDS.MAINNET
|
||||
][1];
|
||||
latestSmartTransaction.status = 'unknown';
|
||||
const store = configureMockStore(middleware)(mockStore);
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Status unknown')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
'A transaction has been successful but we’re unsure what it is. This may be due to submitting another transaction while this swap was processing.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Close')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('cancels a transaction', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Publicly submitting your Swap...')).toBeInTheDocument();
|
||||
const cancelLink = getByText('Cancel swap for ~0');
|
||||
expect(cancelLink).toBeInTheDocument();
|
||||
fireEvent.click(cancelLink);
|
||||
expect(
|
||||
getByText('Trying to cancel your transaction...'),
|
||||
).toBeInTheDocument();
|
||||
expect(cancelLink).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicks on the Close button', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const { getByText } = renderWithProvider(<SmartTransactionStatus />, store);
|
||||
expect(getByText('Publicly submitting your Swap...')).toBeInTheDocument();
|
||||
const closeButton = getByText('Close');
|
||||
expect(closeButton).toBeInTheDocument();
|
||||
fireEvent.click(closeButton);
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider } from '../../../../test/jest';
|
||||
import { renderWithProvider, fireEvent } from '../../../../test/jest';
|
||||
import SwapsFooter from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
@ -25,4 +25,15 @@ describe('SwapsFooter', () => {
|
||||
expect(getByText('Terms of service')).toBeInTheDocument();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('clicks on a block explorer link', () => {
|
||||
global.platform = { openTab: jest.fn() };
|
||||
const props = createProps();
|
||||
const { getByText } = renderWithProvider(<SwapsFooter {...props} />);
|
||||
expect(getByText(props.submitText)).toBeInTheDocument();
|
||||
fireEvent.click(getByText('Terms of service'));
|
||||
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||
url: 'https://metamask.io/terms.html',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -34,6 +34,8 @@ import {
|
||||
getSwapsLivenessForNetwork,
|
||||
countDecimals,
|
||||
showRemainingTimeInMinAndSec,
|
||||
getFeeForSmartTransaction,
|
||||
formatSwapsValueForDisplay,
|
||||
} from './swaps.util';
|
||||
|
||||
jest.mock('../../../shared/lib/storage-helpers', () => ({
|
||||
@ -534,6 +536,10 @@ describe('Swaps Util', () => {
|
||||
shouldEnableDirectWrapping(CHAIN_IDS.MAINNET, WETH_CONTRACT_ADDRESS),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if source and destination tokens are undefined', () => {
|
||||
expect(shouldEnableDirectWrapping(CHAIN_IDS.MAINNET)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showRemainingTimeInMinAndSec', () => {
|
||||
@ -551,9 +557,48 @@ describe('Swaps Util', () => {
|
||||
});
|
||||
|
||||
describe('getFeeForSmartTransaction', () => {
|
||||
it('returns estimated for for STX', () => {
|
||||
// TODO: Implement tests for this function.
|
||||
expect(true).toBe(true);
|
||||
it('returns estimated fee for STX', () => {
|
||||
const expected = {
|
||||
feeInUsd: '0.02',
|
||||
feeInFiat: '$0.02',
|
||||
feeInEth: '0.00323 ETH',
|
||||
rawEthFee: '0.00323',
|
||||
};
|
||||
const actual = getFeeForSmartTransaction({
|
||||
chainId: CHAIN_IDS.MAINNET,
|
||||
currentCurrency: 'usd',
|
||||
conversionRate: 5,
|
||||
USDConversionRate: 5,
|
||||
nativeCurrencySymbol: 'ETH',
|
||||
feeInWeiDec: 3225623412028924,
|
||||
});
|
||||
expect(actual).toMatchObject(expected);
|
||||
});
|
||||
|
||||
it('returns estimated fee for STX for JPY currency', () => {
|
||||
const expected = {
|
||||
feeInUsd: '0.02',
|
||||
feeInFiat: '£0.02',
|
||||
feeInEth: '0.00323 ETH',
|
||||
rawEthFee: '0.00323',
|
||||
};
|
||||
const actual = getFeeForSmartTransaction({
|
||||
chainId: CHAIN_IDS.MAINNET,
|
||||
currentCurrency: 'gbp',
|
||||
conversionRate: 5,
|
||||
USDConversionRate: 5,
|
||||
nativeCurrencySymbol: 'ETH',
|
||||
feeInWeiDec: 3225623412028924,
|
||||
});
|
||||
expect(actual).toMatchObject(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatSwapsValueForDisplay', () => {
|
||||
it('gets swaps value for display', () => {
|
||||
expect(formatSwapsValueForDisplay('39.6493201125465000000')).toBe(
|
||||
'39.6493201125',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider } from '../../../../test/jest';
|
||||
import { renderWithProvider, fireEvent } from '../../../../test/jest';
|
||||
import ViewOnBlockExplorer from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
@ -20,4 +20,17 @@ describe('ViewOnBlockExplorer', () => {
|
||||
expect(getByText('View Swap at etherscan.io')).toBeInTheDocument();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('clicks on the block explorer link', () => {
|
||||
global.platform = { openTab: jest.fn() };
|
||||
const { getByText } = renderWithProvider(
|
||||
<ViewOnBlockExplorer {...createProps()} />,
|
||||
);
|
||||
const link = getByText('View Swap at etherscan.io');
|
||||
expect(link).toBeInTheDocument();
|
||||
fireEvent.click(link);
|
||||
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||
url: 'https://etherscan.io',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -38,6 +38,7 @@ exports[`ViewQuote renders the component with EIP-1559 enabled 2`] = `
|
||||
</span>
|
||||
<span
|
||||
class=""
|
||||
data-testid="exchange-rate-display__base-symbol"
|
||||
>
|
||||
DAI
|
||||
</span>
|
||||
@ -54,6 +55,7 @@ exports[`ViewQuote renders the component with EIP-1559 enabled 2`] = `
|
||||
</span>
|
||||
<div
|
||||
class="exchange-rate-display__switch-arrows"
|
||||
data-testid="exchange-rate-display__switch-arrows"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
@ -110,6 +112,7 @@ exports[`ViewQuote renders the component with initial props 2`] = `
|
||||
</span>
|
||||
<span
|
||||
class=""
|
||||
data-testid="exchange-rate-display__base-symbol"
|
||||
>
|
||||
DAI
|
||||
</span>
|
||||
@ -126,6 +129,7 @@ exports[`ViewQuote renders the component with initial props 2`] = `
|
||||
</span>
|
||||
<div
|
||||
class="exchange-rate-display__switch-arrows"
|
||||
data-testid="exchange-rate-display__switch-arrows"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
|
@ -659,6 +659,7 @@ export default function ViewQuote() {
|
||||
|
||||
const metaMaskFee = usedQuote.fee;
|
||||
|
||||
/* istanbul ignore next */
|
||||
const onFeeCardTokenApprovalClick = () => {
|
||||
trackEditSpendLimitOpened();
|
||||
dispatch(
|
||||
@ -891,7 +892,9 @@ export default function ViewQuote() {
|
||||
'view-quote__content_modal': disableSubmissionDueToPriceWarning,
|
||||
})}
|
||||
>
|
||||
{selectQuotePopoverShown && (
|
||||
{
|
||||
/* istanbul ignore next */
|
||||
selectQuotePopoverShown && (
|
||||
<SelectQuotePopover
|
||||
quoteDataRows={renderablePopoverData}
|
||||
onClose={() => setSelectQuotePopoverShown(false)}
|
||||
@ -903,7 +906,8 @@ export default function ViewQuote() {
|
||||
smartTransactionsEnabled && smartTransactionsOptInStatus
|
||||
}
|
||||
/>
|
||||
)}
|
||||
)
|
||||
}
|
||||
|
||||
<div
|
||||
className={classnames('view-quote__warning-wrapper', {
|
||||
@ -914,7 +918,10 @@ export default function ViewQuote() {
|
||||
{(showInsufficientWarning || tokenBalanceUnavailable) && (
|
||||
<ActionableMessage
|
||||
message={actionableBalanceErrorMessage}
|
||||
onClose={() => setWarningHidden(true)}
|
||||
onClose={
|
||||
/* istanbul ignore next */
|
||||
() => setWarningHidden(true)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@ -971,10 +978,13 @@ export default function ViewQuote() {
|
||||
onTokenApprovalClick={onFeeCardTokenApprovalClick}
|
||||
metaMaskFee={String(metaMaskFee)}
|
||||
numberOfQuotes={Object.values(quotes).length}
|
||||
onQuotesClick={() => {
|
||||
onQuotesClick={
|
||||
/* istanbul ignore next */
|
||||
() => {
|
||||
trackAllAvailableQuotesOpened();
|
||||
setSelectQuotePopoverShown(true);
|
||||
}}
|
||||
}
|
||||
}
|
||||
chainId={chainId}
|
||||
isBestQuote={isBestQuote}
|
||||
maxPriorityFeePerGasDecGWEI={hexWEIToDecGWEI(
|
||||
@ -986,7 +996,8 @@ export default function ViewQuote() {
|
||||
)}
|
||||
</div>
|
||||
<SwapsFooter
|
||||
onSubmit={() => {
|
||||
onSubmit={
|
||||
/* istanbul ignore next */ () => {
|
||||
setSubmitClicked(true);
|
||||
if (!balanceError) {
|
||||
if (
|
||||
@ -1016,7 +1027,8 @@ export default function ViewQuote() {
|
||||
} else {
|
||||
history.push(`${ASSET_ROUTE}/${destinationToken.address}`);
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
submitText={
|
||||
currentSmartTransactionsEnabled &&
|
||||
smartTransactionsOptInStatus &&
|
||||
|
Loading…
Reference in New Issue
Block a user