diff --git a/e2e/fixtures/fixture-builder.js b/e2e/fixtures/fixture-builder.js index 024f90a6c1a..01da16759e2 100644 --- a/e2e/fixtures/fixture-builder.js +++ b/e2e/fixtures/fixture-builder.js @@ -5,7 +5,8 @@ import { merge } from 'lodash'; import { CustomNetworks, PopularNetworksList } from '../resources/networks.e2e'; import { CHAIN_IDS } from '@metamask/transaction-controller'; -export const DEFAULT_FIXTURE_ACCOUNT = '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3'; +export const DEFAULT_FIXTURE_ACCOUNT = + '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3'; const DAPP_URL = 'localhost'; @@ -627,6 +628,7 @@ class FixtureBuilder { selectedRegionAgg: null, selectedPaymentMethodAgg: null, getStartedAgg: false, + getStartedSell: false, authenticationUrls: [], activationKeys: [], }, @@ -696,8 +698,9 @@ class FixtureBuilder { const { providerConfig } = data; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(networkController.networkConfigurationsByChainId).length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(networkController.networkConfigurationsByChainId).length + 1 + }`; // Define the network configuration const networkConfig = { @@ -776,6 +779,30 @@ class FixtureBuilder { return this; } + withRampsSelectedRegion(region = null) { + const defaultRegion = { + currencies: ['/currencies/fiat/xcd'], + emoji: '🇱🇨', + id: '/regions/lc', + name: 'Saint Lucia', + support: { buy: true, sell: true, recurringBuy: true }, + unsupported: false, + recommended: false, + detected: false, + }; + + // Use the provided region or fallback to the default + this.fixture.state.fiatOrders.selectedRegionAgg = region ?? defaultRegion; + return this; + } + withRampsSelectedPaymentMethod() { + const paymentType = '/payments/debit-credit-card'; + + // Use the provided region or fallback to the default + this.fixture.state.fiatOrders.selectedPaymentMethodAgg = paymentType; + return this; + } + /** * Adds chain switching permission for specific chains. * @param {string[]} chainIds - Array of chain IDs to permit (defaults to ['0x1']), other nexts like linea mainnet 0xe708 @@ -818,9 +845,10 @@ class FixtureBuilder { const fixtures = this.fixture.state.engine.backgroundState; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) - .length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) + .length + 1 + }`; // Define the Ganache network configuration const ganacheNetworkConfig = { @@ -856,9 +884,10 @@ class FixtureBuilder { const sepoliaConfig = CustomNetworks.Sepolia.providerConfig; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) - .length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) + .length + 1 + }`; // Define the Sepolia network configuration const sepoliaNetworkConfig = { @@ -908,8 +937,9 @@ class FixtureBuilder { } = network.providerConfig; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(networkConfigurationsByChainId).length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(networkConfigurationsByChainId).length + 1 + }`; // Define the network configuration const networkConfig = { @@ -988,19 +1018,16 @@ class FixtureBuilder { allTokens: { [CHAIN_IDS.MAINNET]: { [DEFAULT_FIXTURE_ACCOUNT]: tokens, - } - } + }, + }, }); return this; } withIncomingTransactionPreferences(incomingTransactionPreferences) { - merge( - this.fixture.state.engine.backgroundState.PreferencesController, - { - showIncomingTransactions: incomingTransactionPreferences, - }, - ); + merge(this.fixture.state.engine.backgroundState.PreferencesController, { + showIncomingTransactions: incomingTransactionPreferences, + }); return this; } diff --git a/e2e/pages/Ramps/BuildQuoteView.js b/e2e/pages/Ramps/BuildQuoteView.js index 407abb8177d..e7bcd2f1ba1 100644 --- a/e2e/pages/Ramps/BuildQuoteView.js +++ b/e2e/pages/Ramps/BuildQuoteView.js @@ -22,6 +22,10 @@ class BuildQuoteView { async tapCancelButton() { await Gestures.waitAndTap(this.cancelButton); } + async tapDefaultToken(token) { + const tokenName = await Matchers.getElementByText(token); + await Gestures.waitAndTap(tokenName); + } } export default new BuildQuoteView(); diff --git a/e2e/pages/Ramps/TokenSelectBottomSheet.js b/e2e/pages/Ramps/TokenSelectBottomSheet.js new file mode 100644 index 00000000000..0625e6bcf0c --- /dev/null +++ b/e2e/pages/Ramps/TokenSelectBottomSheet.js @@ -0,0 +1,12 @@ +import Matchers from '../../utils/Matchers'; +import Gestures from '../../utils/Gestures'; + +class TokenSelectBottomSheet { + async tapTokenByName(token) { + const tokenName = await Matchers.getElementByText(token); + + await Gestures.waitAndTap(tokenName); + } +} + +export default new TokenSelectBottomSheet(); diff --git a/e2e/resources/blacklistURLs.json b/e2e/resources/blacklistURLs.json index e8b620c8ca8..f337d71278b 100644 --- a/e2e/resources/blacklistURLs.json +++ b/e2e/resources/blacklistURLs.json @@ -14,6 +14,10 @@ ".*phishing-detection.cx.metamask.io/.*", ".*eth.llamarpc.com/.*", ".*token-api.metaswap.codefi.network/.*", - ".*gas.api.cx.metamask.io/networks/*" + ".*gas.api.cx.metamask.io/networks/.*", + ".*clients3.google.com/generate_204.*", + ".*pulse.walletconnect.org/batch.*", + ".*accounts.api.cx.metamask.io/v2/accounts/.*", + ".*exp.host/--/api/v2/development-sessions/.*" ] } diff --git a/e2e/specs/networks/add-custom-rpc.spec.js b/e2e/specs/networks/add-custom-rpc.spec.js index cd8269aa2d2..d0d53ce26a5 100644 --- a/e2e/specs/networks/add-custom-rpc.spec.js +++ b/e2e/specs/networks/add-custom-rpc.spec.js @@ -20,7 +20,7 @@ import { CustomNetworks } from '../../resources/networks.e2e'; const fixtureServer = new FixtureServer(); -describe(SmokeCore('Custom RPC Tests'), () => { +describe('Custom RPC Tests', () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder().build(); diff --git a/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js b/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js new file mode 100644 index 00000000000..a999cb28548 --- /dev/null +++ b/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js @@ -0,0 +1,57 @@ +'use strict'; +import TestHelpers from '../../helpers'; + +import { loginToApp } from '../../viewHelper'; +import { withFixtures } from '../../fixtures/fixture-helper'; +import { SmokeCore } from '../../tags'; +import FixtureBuilder from '../../fixtures/fixture-builder'; + +import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; +import BuyGetStartedView from '../../pages/Ramps/BuyGetStartedView'; + +import Assertions from '../../utils/Assertions'; +import NetworkAddedBottomSheet from '../../pages/Network/NetworkAddedBottomSheet'; +import NetworkApprovalBottomSheet from '../../pages/Network/NetworkApprovalBottomSheet'; +import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; + +describe(SmokeCore('Buy Crypto Deeplinks'), () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + beforeEach(async () => { + jest.setTimeout(150000); + }); + + it('should deep link to onramp on Base network', async () => { + const BuyDeepLink = + 'metamask://buy?chainId=8453&address=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&amount=12'; + + await withFixtures( + { + fixture: new FixtureBuilder().withRampsSelectedRegion().build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + await device.sendToHome(); + await device.launchApp({ + url: BuyDeepLink, + }); + + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await BuyGetStartedView.tapGetStartedButton(); + + await Assertions.checkIfVisible(NetworkApprovalBottomSheet.container); + await NetworkApprovalBottomSheet.tapApproveButton(); + await NetworkAddedBottomSheet.tapSwitchToNetwork(); + await Assertions.checkIfVisible(NetworkEducationModal.container); + await NetworkEducationModal.tapGotItButton(); + await Assertions.checkIfTextIsDisplayed('USD Coin'); + }, + ); + }); +}); diff --git a/e2e/specs/ramps/deeplink-to-buy-flow.spec.js b/e2e/specs/ramps/deeplink-to-buy-flow.spec.js new file mode 100644 index 00000000000..0817a1949fa --- /dev/null +++ b/e2e/specs/ramps/deeplink-to-buy-flow.spec.js @@ -0,0 +1,55 @@ +'use strict'; +import TestHelpers from '../../helpers'; + +import { loginToApp } from '../../viewHelper'; +import { withFixtures } from '../../fixtures/fixture-helper'; +import { SmokeCore } from '../../tags'; +import FixtureBuilder from '../../fixtures/fixture-builder'; + +import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; +import BuyGetStartedView from '../../pages/Ramps/BuyGetStartedView'; + +import BuildQuoteView from '../../pages/Ramps/BuildQuoteView'; +import TokenSelectBottomSheet from '../../pages/Ramps/TokenSelectBottomSheet'; +import Assertions from '../../utils/Assertions'; + +describe(SmokeCore('Buy Crypto Deeplinks'), () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + beforeEach(async () => { + jest.setTimeout(150000); + }); + it('should deep link to onramp ETH', async () => { + const buyLink = 'metamask://buy?chainId=1&amount=275'; + + await withFixtures( + { + fixture: new FixtureBuilder() + .withRampsSelectedPaymentMethod() + .withRampsSelectedRegion() + .build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + await device.sendToHome(); + await device.launchApp({ + url: buyLink, + }); + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await BuyGetStartedView.tapGetStartedButton(); + await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); + await BuildQuoteView.tapDefaultToken('Ethereum'); + + await TokenSelectBottomSheet.tapTokenByName('DAI'); + await Assertions.checkIfTextIsDisplayed('Dai Stablecoin'); + await Assertions.checkIfTextIsDisplayed('$275'); + }, + ); + }); +}); diff --git a/e2e/specs/ramps/deeplink-to-sell-flow.spec.js b/e2e/specs/ramps/deeplink-to-sell-flow.spec.js new file mode 100644 index 00000000000..49b43b58cf2 --- /dev/null +++ b/e2e/specs/ramps/deeplink-to-sell-flow.spec.js @@ -0,0 +1,89 @@ +'use strict'; +import { loginToApp } from '../../viewHelper'; + +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { withFixtures } from '../../fixtures/fixture-helper'; + +import TestHelpers from '../../helpers'; +import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; +import { SmokeCore } from '../../tags'; + +import BuildQuoteView from '../../pages/Ramps/BuildQuoteView'; +import Assertions from '../../utils/Assertions'; +import NetworkApprovalBottomSheet from '../../pages/Network/NetworkApprovalBottomSheet'; +import NetworkAddedBottomSheet from '../../pages/Network/NetworkAddedBottomSheet'; +import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; + +describe(SmokeCore('Sell Crypto Deeplinks'), () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + beforeEach(async () => { + jest.setTimeout(150000); + }); + it('should deep link to offramp ETH', async () => { + const sellDeepLinkURL = + 'metamask://sell?chainId=1&address=0x0000000000000000000000000000000000000000&amount=50'; + const franceRegion = { + currencies: ['/currencies/fiat/eur'], + emoji: '🇫🇷', + id: '/regions/fr', + name: 'France', + support: { buy: true, sell: true, recurringBuy: true }, + unsupported: false, + recommended: false, + detected: false, + }; + await withFixtures( + { + fixture: new FixtureBuilder() + .withRampsSelectedRegion(franceRegion) + .build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + + await device.openURL({ + url: sellDeepLinkURL, + }); + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await SellGetStartedView.tapGetStartedButton(); + await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); + + await Assertions.checkIfTextIsDisplayed('50 ETH'); + }, + ); + }); + it('Should deep link to an unsupported network in the off-ramp flow', async () => { + const unsupportedNetworkSellDeepLink = 'metamask://sell?chainId=56'; + + await withFixtures( + { + fixture: new FixtureBuilder().withRampsSelectedRegion().build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + + await device.openURL({ + url: unsupportedNetworkSellDeepLink, + }); + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await SellGetStartedView.tapGetStartedButton(); + + await NetworkApprovalBottomSheet.tapApproveButton(); + await NetworkAddedBottomSheet.tapSwitchToNetwork(); + await Assertions.checkIfVisible(NetworkEducationModal.container); + await NetworkEducationModal.tapGotItButton(); + }, + ); + }); +});