From c8067e93518ace6d2472f026e94672b457bafb3a Mon Sep 17 00:00:00 2001 From: Daniel <80175477+dan437@users.noreply.github.com> Date: Tue, 4 Oct 2022 18:55:05 +0200 Subject: [PATCH] Add more unit / integration tests for Swaps (#16040) --- jest.config.js | 2 +- test/jest/mock-store.js | 17 +- ui/ducks/swaps/swaps.js | 2 +- ui/ducks/swaps/swaps.test.js | 710 +++++++++++++++++- .../__snapshots__/awaiting-swap.test.js.snap | 2 +- ui/pages/swaps/awaiting-swap/awaiting-swap.js | 1 + .../swaps/awaiting-swap/awaiting-swap.test.js | 128 +++- ui/pages/swaps/build-quote/build-quote.js | 54 +- .../swaps/build-quote/build-quote.test.js | 120 ++- .../create-new-swap/create-new-swap.test.js | 53 ++ .../dropdown-input-pair.test.js | 15 + .../dropdown-search-list.test.js.snap | 1 + .../dropdown-search-list.js | 4 + .../dropdown-search-list.test.js | 19 + .../exchange-rate-display.test.js.snap | 2 + .../exchange-rate-display.js | 2 + .../exchange-rate-display.test.js | 16 +- .../__snapshots__/fee-card.test.js.snap | 29 + ui/pages/swaps/fee-card/fee-card.js | 2 + ui/pages/swaps/fee-card/fee-card.test.js | 22 + .../main-quote-summary.test.js.snap | 2 + .../searchable-item-list.test.js.snap | 1 + .../item-list.component.test.js.snap | 47 ++ .../item-list/item-list.component.js | 2 + .../item-list/item-list.component.test.js | 82 ++ .../list-item-search.component.test.js | 107 +++ .../quote-details/quote-details.test.js | 33 + .../__snapshots__/sort-list.test.js.snap | 4 + .../sort-list/sort-list.js | 5 + .../sort-list/sort-list.test.js | 30 +- .../slippage-buttons.test.js.snap | 4 +- .../slippage-buttons/slippage-buttons.js | 1 + .../slippage-buttons/slippage-buttons.test.js | 85 ++- .../smart-transaction-status.test.js | 129 ++++ .../swaps/swaps-footer/swaps-footer.test.js | 13 +- ui/pages/swaps/swaps.util.test.js | 51 +- .../view-on-block-explorer.test.js | 15 +- .../__snapshots__/view-quote.test.js.snap | 4 + ui/pages/swaps/view-quote/view-quote.js | 104 +-- 39 files changed, 1800 insertions(+), 120 deletions(-) create mode 100644 ui/pages/swaps/searchable-item-list/item-list/__snapshots__/item-list.component.test.js.snap create mode 100644 ui/pages/swaps/searchable-item-list/item-list/item-list.component.test.js create mode 100644 ui/pages/swaps/searchable-item-list/list-item-search/list-item-search.component.test.js create mode 100644 ui/pages/swaps/select-quote-popover/quote-details/quote-details.test.js diff --git a/jest.config.js b/jest.config.js index 38f289e50..1f687bb81 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,7 +11,7 @@ module.exports = { coverageThreshold: { global: { branches: 44, - functions: 42, + functions: 46.8, lines: 52, statements: 52, }, diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index 54345e831..334d3fe85 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -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', diff --git a/ui/ducks/swaps/swaps.js b/ui/ducks/swaps/swaps.js index 0cfc8ae76..87303d980 100644 --- a/ui/ducks/swaps/swaps.js +++ b/ui/ducks/swaps/swaps.js @@ -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', diff --git a/ui/ducks/swaps/swaps.test.js b/ui/ducks/swaps/swaps.test.js index e103ed37b..547fa2af1 100644 --- a/ui/ducks/swaps/swaps.test.js +++ b/ui/ducks/swaps/swaps.test.js @@ -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); + }); + }); + }); }); diff --git a/ui/pages/swaps/awaiting-swap/__snapshots__/awaiting-swap.test.js.snap b/ui/pages/swaps/awaiting-swap/__snapshots__/awaiting-swap.test.js.snap index 3f523d5d1..b06bfbba7 100644 --- a/ui/pages/swaps/awaiting-swap/__snapshots__/awaiting-swap.test.js.snap +++ b/ui/pages/swaps/awaiting-swap/__snapshots__/awaiting-swap.test.js.snap @@ -10,7 +10,7 @@ exports[`AwaitingSwap renders the component with initial props 1`] = ` - ETH + USDC will be added to your account once this transaction has processed. diff --git a/ui/pages/swaps/awaiting-swap/awaiting-swap.js b/ui/pages/swaps/awaiting-swap/awaiting-swap.js index 5db7ce571..d8b21f44d 100644 --- a/ui/pages/swaps/awaiting-swap/awaiting-swap.js +++ b/ui/pages/swaps/awaiting-swap/awaiting-swap.js @@ -283,6 +283,7 @@ export default function AwaitingSwap({ ) : null} { + /* istanbul ignore next */ if (errorKey === OFFLINE_FOR_MAINTENANCE) { await dispatch(prepareToLeaveSwaps()); history.push(DEFAULT_ROUTE); diff --git a/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js b/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js index 5bc56817c..923a9c48f 100644 --- a/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js +++ b/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js @@ -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( , 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( + , + 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( + , + 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( + , + 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( + , + 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( + , + 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( + , + 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(); + }); }); diff --git a/ui/pages/swaps/build-quote/build-quote.js b/ui/pages/swaps/build-quote/build-quote.js index 9171037fe..40429ebbf 100644 --- a/ui/pages/swaps/build-quote/build-quote.js +++ b/ui/pages/swaps/build-quote/build-quote.js @@ -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({
} 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,30 +866,33 @@ export default function BuildQuote({ )} { - // 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, - // we want to cancel it and fetch quotes from here. - if (timeoutIdForQuotesPrefetching) { - clearTimeout(timeoutIdForQuotesPrefetching); - dispatch( - fetchQuotesAndSetQuoteState( - history, - fromTokenInputValue, - maxSlippage, - trackEvent, - ), - ); - } else if (areQuotesPresent) { - // If there are prefetched quotes already, go directly to the View Quote page. - history.push(VIEW_QUOTE_ROUTE); - } else { - // If the "Review swap" button was clicked while quotes are being fetched, go to the Loading Quotes page. - await dispatch(setBackgroundSwapRouteState('loading')); - history.push(LOADING_QUOTES_ROUTE); + 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, + // we want to cancel it and fetch quotes from here. + if (timeoutIdForQuotesPrefetching) { + clearTimeout(timeoutIdForQuotesPrefetching); + dispatch( + fetchQuotesAndSetQuoteState( + history, + fromTokenInputValue, + maxSlippage, + trackEvent, + ), + ); + } else if (areQuotesPresent) { + // If there are prefetched quotes already, go directly to the View Quote page. + history.push(VIEW_QUOTE_ROUTE); + } else { + // If the "Review swap" button was clicked while quotes are being fetched, go to the Loading Quotes page. + await dispatch(setBackgroundSwapRouteState('loading')); + history.push(LOADING_QUOTES_ROUTE); + } } - }} + } submitText={t('swapReviewSwap')} disabled={isReviewSwapButtonDisabled} hideCancel diff --git a/ui/pages/swaps/build-quote/build-quote.test.js b/ui/pages/swaps/build-quote/build-quote.test.js index 79b2584d9..8178566c9 100644 --- a/ui/pages/swaps/build-quote/build-quote.test.js +++ b/ui/pages/swaps/build-quote/build-quote.test.js @@ -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(, 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( + , + 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(, 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(, 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(, 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(, store); + const maxLink = getByText('Max'); + fireEvent.click(maxLink); + expect(setFromTokenInputValue).toHaveBeenCalled(); + }); }); diff --git a/ui/pages/swaps/create-new-swap/create-new-swap.test.js b/ui/pages/swaps/create-new-swap/create-new-swap.test.js index 53835efff..f0161a3c1 100644 --- a/ui/pages/swaps/create-new-swap/create-new-swap.test.js +++ b/ui/pages/swaps/create-new-swap/create-new-swap.test.js @@ -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( + , + store, + ); + await fireEvent.click(getByText('Create a new swap')); + expect(setSwapFromTokenMock).toHaveBeenCalledTimes(1); + expect(navigateBackToBuildQuoteMock).toHaveBeenCalledTimes(1); + }); }); diff --git a/ui/pages/swaps/dropdown-input-pair/dropdown-input-pair.test.js b/ui/pages/swaps/dropdown-input-pair/dropdown-input-pair.test.js index 0f09cbf81..e9f319d25 100644 --- a/ui/pages/swaps/dropdown-input-pair/dropdown-input-pair.test.js +++ b/ui/pages/swaps/dropdown-input-pair/dropdown-input-pair.test.js @@ -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( + , + store, + ); + fireEvent.change(getByPlaceholderText('0'), { + target: { value: 1.1 }, + }); + expect(props.onInputChange).toHaveBeenCalledWith('1.1'); + }); }); diff --git a/ui/pages/swaps/dropdown-search-list/__snapshots__/dropdown-search-list.test.js.snap b/ui/pages/swaps/dropdown-search-list/__snapshots__/dropdown-search-list.test.js.snap index e92d6b8cf..d863077c5 100644 --- a/ui/pages/swaps/dropdown-search-list/__snapshots__/dropdown-search-list.test.js.snap +++ b/ui/pages/swaps/dropdown-search-list/__snapshots__/dropdown-search-list.test.js.snap @@ -4,6 +4,7 @@ exports[`DropdownSearchList renders the component with initial props 1`] = `