diff --git a/apps/ledger-live-desktop/tests/page/speculos.page.ts b/apps/ledger-live-desktop/tests/page/speculos.page.ts index 109b7d2c959d..107086d9401d 100644 --- a/apps/ledger-live-desktop/tests/page/speculos.page.ts +++ b/apps/ledger-live-desktop/tests/page/speculos.page.ts @@ -3,9 +3,9 @@ import { step } from "tests/misc/reporters/step"; import { pressBoth, pressUntilTextFound, - waitFor, containsSubstringInEvent, activateLedgerSync, + expectValidAddressDevice, } from "@ledgerhq/live-common/e2e/speculos"; import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { expect } from "@playwright/test"; @@ -29,26 +29,7 @@ import { delegateSolana, sendSolana } from "tests/families/solana"; export class SpeculosPage extends AppPage { @step("Verify receive address correctness on device") async expectValidAddressDevice(account: Account, addressDisplayed: string) { - let deviceLabels: string[]; - - switch (account.currency) { - case Currency.SOL: - deviceLabels = [DeviceLabels.PUBKEY, DeviceLabels.APPROVE, DeviceLabels.REJECT]; - break; - case Currency.DOT: - case Currency.ATOM: - deviceLabels = [DeviceLabels.ADDRESS, DeviceLabels.CAPS_APPROVE, DeviceLabels.CAPS_REJECT]; - break; - default: - deviceLabels = [DeviceLabels.ADDRESS, DeviceLabels.APPROVE, DeviceLabels.REJECT]; - break; - } - - await waitFor(deviceLabels[0]); - const events = await pressUntilTextFound(deviceLabels[1]); - const isAddressCorrect = containsSubstringInEvent(addressDisplayed, events); - expect(isAddressCorrect).toBeTruthy(); - await pressBoth(); + await expectValidAddressDevice(account, addressDisplayed); } @step("Activate Ledger Sync") diff --git a/apps/ledger-live-mobile/e2e/page/accounts/account.page.ts b/apps/ledger-live-mobile/e2e/page/accounts/account.page.ts index 36dcfe097b34..66d2a749ef82 100644 --- a/apps/ledger-live-mobile/e2e/page/accounts/account.page.ts +++ b/apps/ledger-live-mobile/e2e/page/accounts/account.page.ts @@ -12,6 +12,7 @@ export default class AccountPage { operationHistorySectionId = (accountId: string) => `operations-history-${accountId}`; accountScreenScrollView = "account-screen-scrollView"; accountAdvancedLogsId = "account-advanced-logs"; + receiveButton = () => getElementById("account-quick-action-button-Receive"); @Step("Open account settings") async openAccountSettings() { @@ -54,4 +55,9 @@ export default class AccountPage { const advancedLogsJson = advancedLogsText ? JSON.parse(advancedLogsText) : null; jestExpect(advancedLogsJson).toHaveProperty("index", indexNumber); } + + @Step("Tap on receive button") + async tapReceive() { + await tapByElement(this.receiveButton()); + } } diff --git a/apps/ledger-live-mobile/e2e/page/index.ts b/apps/ledger-live-mobile/e2e/page/index.ts index 0aafcb5a397d..428c72bd49cc 100644 --- a/apps/ledger-live-mobile/e2e/page/index.ts +++ b/apps/ledger-live-mobile/e2e/page/index.ts @@ -22,6 +22,7 @@ import ReceivePage from "./trade/receive.page"; import SendPage from "./trade/send.page"; import SettingsGeneralPage from "./settings/settingsGeneral.page"; import SettingsPage from "./settings/settings.page"; +import SpeculosPage from "./speculos.page"; import StakePage from "./trade/stake.page"; import SwapPage from "./trade/swap.page"; import TransfertMenuDrawer from "./wallet/transferMenu.drawer"; @@ -75,6 +76,7 @@ export class Application { public send = new SendPage(); public settings = new SettingsPage(); public settingsGeneral = new SettingsGeneralPage(); + public speculos = new SpeculosPage(); public stake = new StakePage(); public swap = new SwapPage(); public transfertMenu = new TransfertMenuDrawer(); diff --git a/apps/ledger-live-mobile/e2e/page/speculos.page.ts b/apps/ledger-live-mobile/e2e/page/speculos.page.ts new file mode 100644 index 000000000000..7dbdb37596fc --- /dev/null +++ b/apps/ledger-live-mobile/e2e/page/speculos.page.ts @@ -0,0 +1,9 @@ +import { expectValidAddressDevice } from "@ledgerhq/live-common/e2e/speculos"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +export default class SpeculosPage { + @Step("Verify receive address correctness on device") + async expectValidAddressDevice(account: Account, addressDisplayed: string) { + await expectValidAddressDevice(account, addressDisplayed); + } +} diff --git a/apps/ledger-live-mobile/e2e/page/trade/receive.page.ts b/apps/ledger-live-mobile/e2e/page/trade/receive.page.ts index ae6306c4be0b..ad20f4690f19 100644 --- a/apps/ledger-live-mobile/e2e/page/trade/receive.page.ts +++ b/apps/ledger-live-mobile/e2e/page/trade/receive.page.ts @@ -4,6 +4,7 @@ import { getElementByText, getTextOfElement, openDeeplink, + scrollToId, tapById, waitForElementById, } from "../../helpers"; @@ -32,10 +33,17 @@ export default class ReceivePage { step2HeaderTitle = () => getElementById(this.step2HeaderTitleId); titleReceiveConfirmationPageId = (t: string) => `receive-confirmation-title-${t}`; accountNameReceiveId = (t: string) => `receive-account-name-${t}`; + receivePageScrollViewId = "receive-screen-scrollView"; step2Accounts = () => getElementById("receive-header-step2-accounts"); step2Networks = () => getElementById("receive-header-step2-networks"); + tronNewAddressWarningId = "tron-receive-newAddress-warning"; + tronNewAddressWarningDescription = () => + getElementById(`${this.tronNewAddressWarningId}-description`); + tronNewAddressWarningText = + "You first need to send at least 0.1 TRX to this address to activate it."; + async openViaDeeplink() { await openDeeplink(baseLink); } @@ -83,6 +91,7 @@ export default class ReceivePage { await tapById(CurrencyRowId); } + @Step("Accept to verify address") async selectVerifyAddress() { await waitForElementById(this.buttonVerifyAddressId); await tapById(this.buttonVerifyAddressId); @@ -98,6 +107,12 @@ export default class ReceivePage { jestExpect(await getTextOfElement(this.accountAddress)).toEqual(address); } + @Step("Get the fresh address displayed") + async getFreshAddressDisplayed() { + await waitForElementById(this.accountFreshAddress); + return await getTextOfElement(this.accountFreshAddress); + } + async expectNumberOfAccountInListIsDisplayed(currencyName: string, accountNumber: number) { //set "account" in plural or not in fonction of number account const accountCount: string = accountNumber + " account" + (accountNumber > 1 ? "s" : ""); @@ -141,6 +156,7 @@ export default class ReceivePage { return tapById(this.noVerifyValidateButton); } + @Step("Expect account receive page is displayed") async expectReceivePageIsDisplayed(tickerName: string, accountName: string) { const receiveTitleTickerId = this.titleReceiveConfirmationPageId(tickerName); const accountNameId = this.accountNameReceiveId(accountName); @@ -150,6 +166,21 @@ export default class ReceivePage { await expect(getElementById(accountNameId)).toBeVisible(); } + @Step("Expect given address is displayed on receive page") + async expectAddressIsCorrect(address: string) { + await expect(getElementById(this.accountAddress)).toHaveText(address); + } + + @Step("Expect tron new address warning") + async expectTronNewAddressWarning() { + await scrollToId(this.tronNewAddressWarningId, this.receivePageScrollViewId); + await expect(getElementById(this.tronNewAddressWarningId)).toBeVisible(); + await expect(this.tronNewAddressWarningDescription()).toHaveText( + this.tronNewAddressWarningText, + ); + } + + @Step("Refuse to verify address") async doNotVerifyAddress() { await this.selectDontVerifyAddress(); await this.selectReconfirmDontVerify(); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddress.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddress.ts new file mode 100644 index 000000000000..105d371f0706 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddress.ts @@ -0,0 +1,42 @@ +import { CLI } from "../../../utils/cliUtils"; +import { Application } from "../../../page"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +export async function runVerifyAddressTest(account: Account, tmsLink: string) { + const app = new Application(); + + describe(`Verify Address - ${account.currency.name}`, () => { + beforeAll(async () => { + await app.init({ + speculosApp: account.currency.speculosApp, + cliCommands: [ + () => { + return CLI.liveData({ + currency: account.currency.currencyId, + index: account.index, + appjson: app.userdataPath, + add: true, + }); + }, + ], + }); + await app.portfolio.waitForPortfolioPageToLoad(); + }); + + $TmsLink(tmsLink); + it(`Verify address on ${account.currency.name}`, async () => { + await app.accounts.openViaDeeplink(); + await app.common.goToAccountByName(account.accountName); + await app.account.tapReceive(); + await app.receive.selectVerifyAddress(); + const displayedAddress = await app.receive.getFreshAddressDisplayed(); + await app.speculos.expectValidAddressDevice(account, displayedAddress); + await app.receive.expectReceivePageIsDisplayed(account.currency.ticker, account.accountName); + await app.receive.expectAddressIsCorrect(displayedAddress); + }); + + afterAll(async () => { + await app?.common.removeSpeculos(); + }); + }); +} diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressATOM.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressATOM.spec.ts new file mode 100644 index 000000000000..2f80a0891267 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressATOM.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.ATOM_1, "B2CQA-2560, B2CQA-2694"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBCH.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBCH.spec.ts new file mode 100644 index 000000000000..4dfa50cdc13f --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBCH.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.BCH_1, "B2CQA-2558, B2CQA-2693"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBSC.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBSC.spec.ts new file mode 100644 index 000000000000..f2851501914a --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBSC.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.BSC_1, "B2CQA-2686, B2CQA-2696"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBTC.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBTC.spec.ts new file mode 100644 index 000000000000..9fe21e854ce5 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressBTC.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.BTC_NATIVE_SEGWIT_1, "B2CQA-2559, B2CQA-2687"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressDOT.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressDOT.spec.ts new file mode 100644 index 000000000000..cc525516ad04 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressDOT.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.DOT_1, "B2CQA-2562, B2CQA-2691"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressETH.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressETH.spec.ts new file mode 100644 index 000000000000..c584c4e164b5 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressETH.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.ETH_1, "B2CQA-2561, B2CQA-2688"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressSOL.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressSOL.spec.ts new file mode 100644 index 000000000000..6d2dc9aa1d47 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressSOL.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.SOL_1, "B2CQA-2563, B2CQA-2689"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressTRX.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressTRX.spec.ts new file mode 100644 index 000000000000..15f21956c506 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressTRX.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.TRX_1, "B2CQA-2565, B2CQA-2690"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressXRP.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressXRP.spec.ts new file mode 100644 index 000000000000..87920ece86eb --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressXRP.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.XRP_1, "B2CQA-2566, B2CQA-2692"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressXTZ.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressXTZ.spec.ts new file mode 100644 index 000000000000..947829c6435f --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyAddressXTZ.spec.ts @@ -0,0 +1,4 @@ +import { runVerifyAddressTest } from "./verifyAddress"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +runVerifyAddressTest(Account.XTZ_1, "B2CQA-2564, B2CQA-2695"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyEmptyAddressTRX.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyEmptyAddressTRX.spec.ts new file mode 100644 index 000000000000..b24b5a98afb8 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/verifyAddress/verifyEmptyAddressTRX.spec.ts @@ -0,0 +1,39 @@ +import { CLI } from "../../../utils/cliUtils"; +import { Application } from "../../../page"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; + +const app = new Application(); +const account = Account.TRX_3; + +describe(`Verify Address warnings - ${account.currency.name}`, () => { + beforeAll(async () => { + await app.init({ + speculosApp: account.currency.speculosApp, + cliCommands: [ + () => { + return CLI.liveData({ + currency: account.currency.currencyId, + index: account.index, + appjson: app.userdataPath, + add: true, + }); + }, + ], + }); + await app.portfolio.waitForPortfolioPageToLoad(); + }); + + $TmsLink("B2CQA-1551"); + it(`Verify address warning for ${account.currency.name}`, async () => { + await app.accounts.openViaDeeplink(); + await app.common.goToAccountByName(account.accountName); + await app.account.tapReceive(); + await app.receive.doNotVerifyAddress(); + await app.receive.expectReceivePageIsDisplayed(account.currency.ticker, account.accountName); + await app.receive.expectTronNewAddressWarning(); + }); + + afterAll(async () => { + await app?.common.removeSpeculos(); + }); +}); diff --git a/apps/ledger-live-mobile/src/components/Alert.tsx b/apps/ledger-live-mobile/src/components/Alert.tsx index 4ed050c78f2e..6f637b95666d 100644 --- a/apps/ledger-live-mobile/src/components/Alert.tsx +++ b/apps/ledger-live-mobile/src/components/Alert.tsx @@ -33,6 +33,7 @@ type Props = { learnMoreUrl?: string; learnMoreIsInternal?: boolean; learnMoreIcon?: IconType; + testID?: string; }; const alertPropsByType: Record< @@ -139,6 +140,7 @@ export default function Alert(props: Props) { learnMoreIsInternal = false, learnMoreIcon, learnMoreTransValues, + testID, } = props; const dismissedBanners = useSelector(dismissedBannersSelector); @@ -164,10 +166,14 @@ export default function Alert(props: Props) { return !isDismissed ? ( - - {title && {title}} + + {title && {title}} {description && ( - + {description} )} diff --git a/apps/ledger-live-mobile/src/components/FabActions/actionsList/account/index.tsx b/apps/ledger-live-mobile/src/components/FabActions/actionsList/account/index.tsx index a7f646386376..1c679ea9e400 100644 --- a/apps/ledger-live-mobile/src/components/FabActions/actionsList/account/index.tsx +++ b/apps/ledger-live-mobile/src/components/FabActions/actionsList/account/index.tsx @@ -34,6 +34,7 @@ export const FabAccountMainActionsComponent: React.FC = numColumns={2} id="two_columns" key="two_columns" + testID="account-quick-action-button" /> ) : ( = numColumns={3} id="three_columns" key="three_columns" + testID="account-quick-action-button" /> )} diff --git a/apps/ledger-live-mobile/src/components/FabActions/actionsList/asset/index.tsx b/apps/ledger-live-mobile/src/components/FabActions/actionsList/asset/index.tsx index b63b2f24b862..27e21889f89e 100644 --- a/apps/ledger-live-mobile/src/components/FabActions/actionsList/asset/index.tsx +++ b/apps/ledger-live-mobile/src/components/FabActions/actionsList/asset/index.tsx @@ -29,6 +29,7 @@ const FabAssetActionsComponent: React.FC = ({ currency, accounts, default numColumns={2} id="asset_two_columns" key="asset_two_columns" + testID="asset-quick-action-button" /> ) : ( = ({ currency, accounts, default numColumns={3} id="asset_three_columns" key="asset_three_columns" + testID="asset-quick-action-button" /> )} diff --git a/apps/ledger-live-mobile/src/components/MarketQuickActions/index.tsx b/apps/ledger-live-mobile/src/components/MarketQuickActions/index.tsx index 3236ea71cc8a..4b62f1f3cd18 100644 --- a/apps/ledger-live-mobile/src/components/MarketQuickActions/index.tsx +++ b/apps/ledger-live-mobile/src/components/MarketQuickActions/index.tsx @@ -44,6 +44,7 @@ export const MarketQuickActions = (quickActionsProps: Required key={quickActionsData.length} numColumns={quickActionsData.length} id="asset_five_columns" + testID="market-quick-action-button" /> ); diff --git a/apps/ledger-live-mobile/src/families/tron/ReceiveConfirmationPostAlert.tsx b/apps/ledger-live-mobile/src/families/tron/ReceiveConfirmationPostAlert.tsx index 5e44dffcf0e0..2e0c0d3a30b5 100644 --- a/apps/ledger-live-mobile/src/families/tron/ReceiveConfirmationPostAlert.tsx +++ b/apps/ledger-live-mobile/src/families/tron/ReceiveConfirmationPostAlert.tsx @@ -12,7 +12,11 @@ export default function ReceiveConfirmationPostAlert({ mainAccount }: Props) { return ( <> {mainAccount.operationsCount === 0 ? ( - + ) : null} diff --git a/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx b/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx index 6c5132e63533..058f4e5d9025 100644 --- a/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx +++ b/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx @@ -70,7 +70,14 @@ function PortfolioQuickActionsBar() { }, ].filter((v: T | undefined): v is T => !!v); - return ; + return ( + + ); } export default PortfolioQuickActionsBar; diff --git a/apps/ledger-live-mobile/src/screens/ReceiveFunds/03-Confirmation.tsx b/apps/ledger-live-mobile/src/screens/ReceiveFunds/03-Confirmation.tsx index 82f4c8fc28b9..65563ed85582 100644 --- a/apps/ledger-live-mobile/src/screens/ReceiveFunds/03-Confirmation.tsx +++ b/apps/ledger-live-mobile/src/screens/ReceiveFunds/03-Confirmation.tsx @@ -285,7 +285,7 @@ function ReceiveConfirmationInner({ navigation, route, account, parentAccount }: return ( - + { return ( @@ -55,6 +56,7 @@ const QuickActionButton = ({ visuallyDisabled={disabled} variant={variant} {...otherProps} + testID={`${testID}-${children}`} > , "renderItem"> & { id: string; + testID?: string; }; const QuickActionList = ({ numColumns = 3, data, id, + testID, ...otherProps }: QuickActionListProps): React.ReactElement => { const renderItem = useCallback( @@ -21,6 +23,7 @@ const QuickActionList = ({ flex={1} mr={(index + 1) % numColumns > 0 && data && index !== data.length - 1 ? 4 : 0} mb={data?.length && index + numColumns < data.length ? 4 : 0} + testID={testID} /> ); },