Skip to content

Commit

Permalink
test: speculos detox send test
Browse files Browse the repository at this point in the history
  • Loading branch information
abdurrahman-ledger committed Jan 3, 2025
1 parent 8d2cf10 commit e6f5697
Show file tree
Hide file tree
Showing 34 changed files with 309 additions and 20 deletions.
4 changes: 4 additions & 0 deletions apps/ledger-live-mobile/e2e/bridge/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ const retryDelay = 500; // Initial retry delay in milliseconds
export function init() {
const wsPort = LaunchArguments.value()["wsPort"] || "8099";
const mock = LaunchArguments.value()["mock"];
const disable_broadcast = LaunchArguments.value()["disable_broadcast"];

log(`[E2E Bridge Client]: wsPort=${wsPort}, mock=${mock}`);

if (mock == "0") setEnv("MOCK", "");
setEnv("DISABLE_TRANSACTION_BROADCAST", disable_broadcast != "0");

if (ws) {
ws.close();
}
Expand Down
14 changes: 14 additions & 0 deletions apps/ledger-live-mobile/e2e/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ export function getWebElementByTag(tag: string, index = 0) {
return web.element(by.web.tag(tag)).atIndex(index);
}

export async function IsIdVisible(id: string | RegExp) {
try {
await waitFor(element(by.id(id)))
.toBeVisible()
.withTimeout(1000);
return true;
} catch {
return false;
}
}

export async function tapById(id: string | RegExp, index = 0) {
return getElementById(id, index).tap();
}
Expand Down Expand Up @@ -180,6 +191,9 @@ export async function launchApp() {
detoxURLBlacklistRegex:
'\\(".*sdk.*.braze.*",".*.googleapis.com/.*",".*clients3.google.com.*"\\)',
mock: getEnv("MOCK") ? getEnv("MOCK") : "0",
disable_broadcast: getEnv("DISABLE_TRANSACTION_BROADCAST")
? getEnv("DISABLE_TRANSACTION_BROADCAST")
: "1",
},
languageAndLocale: {
language: "en-US",
Expand Down
43 changes: 43 additions & 0 deletions apps/ledger-live-mobile/e2e/models/send.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency";
import { Application } from "../page";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";

export async function verifyAppValidationSendInfo(
app: Application,
transaction: Transaction,
amount: string,
) {
const currenciesForValidationAmount = [
Currency.sepETH,
Currency.DOT,
Currency.POL,
Currency.ALGO,
Currency.ADA,
Currency.DOGE,
Currency.SOL,
Currency.TRX,
Currency.XLM,
Currency.XRP,
Currency.ATOM,
Currency.BCH,
];

const currenciesForValidationRecipient = [Currency.sepETH, Currency.POL];
const currenciesForValidationSender = [Currency.ATOM];

const currency = transaction.accountToCredit.currency;
const addressRecipient = transaction.accountToCredit.address;
const addressSender = transaction.accountToDebit.address;

if (currenciesForValidationAmount.includes(currency)) {
await app.send.expectValidationAmount(amount);
}

if (currenciesForValidationRecipient.includes(currency)) {
await app.send.expectValidationAddress(addressRecipient);
}

if (currenciesForValidationSender.includes(currency)) {
await app.send.expectValidationAddress(addressSender);
}
}
15 changes: 14 additions & 1 deletion apps/ledger-live-mobile/e2e/page/accounts/account.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ export default class AccountPage {
accountAdvancedLogRow = () => getElementById("account-advanced-log-row");
accountDeleteRow = () => getElementById("account-settings-delete-row");
accountDeleteConfirm = () => getElementById("delete-account-confirmation-button");
operationHistorySectionId = (accountId: string) => `operations-history-${accountId}`;
operationHistorySection = "operations-history-";
operationHistorySectionRegexp = new RegExp(this.operationHistorySection + ".*");
operationHistorySectionId = (accountId: string) => this.operationHistorySection + accountId;
accountScreenScrollView = "account-screen-scrollView";
accountAdvancedLogsId = "account-advanced-logs";
receiveButton = () => getElementById("account-quick-action-button-Receive");
sendButton = () => getElementById("account-quick-action-button-Send");

@Step("Open account settings")
async openAccountSettings() {
Expand Down Expand Up @@ -41,6 +44,11 @@ export default class AccountPage {
await expect(getElementById(id)).toBeVisible();
}

@Step("Scroll to transaction history")
async scrollToTransactions() {
await scrollToId(this.operationHistorySectionRegexp, this.accountScreenScrollView);
}

@Step("Expect account balance to be visible")
async expectAccountBalanceVisible(accountId: string) {
await expect(this.accountGraph(accountId)).toBeVisible();
Expand All @@ -60,4 +68,9 @@ export default class AccountPage {
async tapReceive() {
await tapByElement(this.receiveButton());
}

@Step("Tap on send button")
async tapSend() {
await tapByElement(this.sendButton());
}
}
7 changes: 7 additions & 0 deletions apps/ledger-live-mobile/e2e/page/common.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class CommonPage {
searchBarId = "common-search-field";
searchBar = () => getElementById(this.searchBarId);
successCloseButtonId = "success-close-button";
successViewDetailsButtonId = "success-view-details-button";
closeButton = () => getElementById("NavigationHeaderCloseButton");

accoundCardId = (id: string) => "account-card-" + id;
Expand Down Expand Up @@ -53,6 +54,12 @@ export default class CommonPage {
await tapById(this.successCloseButtonId);
}

@Step("Tap on view details")
async successViewDetails() {
await waitForElementById(this.successViewDetailsButtonId);
await tapById(this.successViewDetailsButtonId);
}

async selectAccount(accountId: string) {
const id = this.accoundCardId(accountId);
await waitForElementById(id);
Expand Down
7 changes: 6 additions & 1 deletion apps/ledger-live-mobile/e2e/page/speculos.page.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { expectValidAddressDevice } from "@ledgerhq/live-common/e2e/speculos";
import { expectValidAddressDevice, signSendTransaction } from "@ledgerhq/live-common/e2e/speculos";
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";

export default class SpeculosPage {
@Step("Verify receive address correctness on device")
async expectValidAddressDevice(account: Account, addressDisplayed: string) {
await expectValidAddressDevice(account, addressDisplayed);
}

async signSendTransaction(tx: Transaction) {
await signSendTransaction(tx);
}
}
15 changes: 13 additions & 2 deletions apps/ledger-live-mobile/e2e/page/trade/operationDetails.page.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import { getElementById } from "../../helpers";
import { getElementById, scrollToId, waitForElementById } from "../../helpers";
import { expect } from "detox";

export default class OperationDetailsPage {
title = () => getElementById("operationDetails-title");
titleId = "operationDetails-title";
title = () => getElementById(this.titleId);
account = () => getElementById("operationDetails-account");
amount = () => getElementById("operationDetails-amount");
recipientId = "operationDetails-recipient0";

async isOpened() {
await expect(this.title()).toBeVisible();
}

async waitForOperationDetails() {
await waitForElementById(this.titleId);
}

async checkAccount(account: string) {
await expect(this.account()).toHaveText(account);
}

async checkAmount(amount: string) {
await expect(this.amount()).toHaveText(amount);
}

async checkRecipient(recipient: string) {
await scrollToId(this.recipientId);
await expect(getElementById(this.recipientId)).toHaveText(recipient);
}
}
34 changes: 34 additions & 0 deletions apps/ledger-live-mobile/e2e/page/trade/send.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ import {
openDeeplink,
typeTextById,
tapByElement,
IsIdVisible,
} from "../../helpers";
import { expect } from "detox";

const baseLink = "send";

export default class SendPage {
summaryAmount = () => getElementById("send-summary-amount");
summaryRecipient = () => getElementById("send-summary-recipient");
validationAmountId = "send-validation-amount";
validationAddressId = "send-validation-address";
getStep1HeaderTitle = () => getElementById("send-header-step1-title");
recipientContinueButtonId = "recipient-continue-button";
recipientInputId = "recipient-input";
amountInputId = "amount-input";
amountContinueButton = () => getElementById("amount-continue-button");
summaryContinueButton = () => getElementById("summary-continue-button");
highFreeConfirmButtonID = "confirmation-modal-confirm-button";

async openViaDeeplink() {
await openDeeplink(baseLink);
Expand All @@ -42,6 +47,11 @@ export default class SendPage {
await tapById(this.recipientContinueButtonId);
}

async setRecipientAndContinue(address: string) {
await this.setRecipient(address);
await this.recipientContinue();
}

async setAmount(amount: string) {
const element = getElementById(this.amountInputId);
await element.replaceText(amount);
Expand All @@ -52,11 +62,35 @@ export default class SendPage {
await tapByElement(this.amountContinueButton());
}

async setAmountAndContinue(amount: string) {
await this.setAmount(amount);
await this.amountContinue();
}

async summaryContinue() {
await tapByElement(this.summaryContinueButton());
}

async expectSummaryAmount(amount: string) {
await expect(this.summaryAmount()).toHaveText(amount);
}

async expectSummaryRecepient(recipient: string) {
await expect(this.summaryRecipient()).toHaveText(recipient);
}

async dismissHighFeeModal() {
if (await IsIdVisible(this.highFreeConfirmButtonID))
await tapById(this.highFreeConfirmButtonID);
}

async expectValidationAmount(amount: string) {
await waitForElementById(this.validationAmountId);
await expect(getElementById(this.validationAmountId)).toHaveText(amount);
}

async expectValidationAddress(recipient: string) {
await waitForElementById(this.validationAddressId);
await expect(getElementById(this.validationAddressId)).toHaveText(recipient);
}
}
65 changes: 65 additions & 0 deletions apps/ledger-live-mobile/e2e/specs/speculos/send/send.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { verifyAppValidationSendInfo } from "../../../models/send";
import { Application } from "../../../page";
import { CLI } from "../../../utils/cliUtils";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { device } from "detox";

export async function runSendTest(transaction: Transaction, tmsLink: string) {
const app = new Application();

$TmsLink(tmsLink);
describe(`Send flow on ${transaction.accountToCredit.currency.name}`, () => {
beforeAll(async () => {
await app.init({
speculosApp: transaction.accountToCredit.currency.speculosApp,
cliCommands: [
() => {
return CLI.liveData({
currency: transaction.accountToCredit.currency.currencyId,
index: transaction.accountToCredit.index,
add: true,
appjson: app.userdataPath,
});
},
() => {
return CLI.liveData({
currency: transaction.accountToDebit.currency.currencyId,
index: transaction.accountToDebit.index,
add: true,
appjson: app.userdataPath,
});
},
],
});

await app.portfolio.waitForPortfolioPageToLoad();
});

it(`Send from 1 account to another on ${transaction.accountToCredit.currency.name}`, async () => {
await app.accounts.openViaDeeplink();
await app.common.goToAccountByName(transaction.accountToDebit.accountName);
await app.account.tapSend();

const amountWithCode = transaction.amount + " " + transaction.accountToCredit.currency.ticker;

await app.send.setRecipientAndContinue(transaction.accountToCredit.address);
await app.send.setAmountAndContinue(transaction.amount);

await app.send.expectSummaryAmount(amountWithCode);
await app.send.expectSummaryRecepient(transaction.accountToCredit.address);
await app.send.summaryContinue();
await app.send.dismissHighFeeModal();

await verifyAppValidationSendInfo(app, transaction, amountWithCode);

await app.speculos.signSendTransaction(transaction);

await device.disableSynchronization();
await app.common.successViewDetails();

await app.operationDetails.waitForOperationDetails();
await app.operationDetails.checkAccount(transaction.accountToDebit.accountName);
await app.operationDetails.checkRecipient(transaction.accountToCredit.address);
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.ADA_1, Account.ADA_2, "1");
runSendTest(transaction, "B2CQA-2815");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.ALGO_1, Account.ALGO_2, "0.001");
runSendTest(transaction, "B2CQA-2810");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.ATOM_1, Account.ATOM_2, "0.0001");
runSendTest(transaction, "B2CQA-2814");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.BCH_1, Account.BCH_2, "0.0001");
runSendTest(transaction, "B2CQA-2808");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.DOGE_1, Account.DOGE_2, "0.01");
runSendTest(transaction, "B2CQA-2573");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.DOT_1, Account.DOT_2, "0.0001");
runSendTest(transaction, "B2CQA-2809");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.POL_1, Account.POL_2, "0.001");
runSendTest(transaction, "B2CQA-2807");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.SOL_1, Account.SOL_2, "0.000001");
runSendTest(transaction, "B2CQA-2811");
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Account } from "@ledgerhq/live-common/e2e/enum/Account";
import { Transaction } from "@ledgerhq/live-common/e2e/models/Transaction";
import { runSendTest } from "../send/send";

const transaction = new Transaction(Account.sep_ETH_1, Account.sep_ETH_2, "0.00001");
runSendTest(transaction, "B2CQA-2574");
Loading

0 comments on commit e6f5697

Please sign in to comment.