diff --git a/.github/workflows/test-mobile-e2e-reusable.yml b/.github/workflows/test-mobile-e2e-reusable.yml index a7fbb34e8a1e..24ec324da54e 100644 --- a/.github/workflows/test-mobile-e2e-reusable.yml +++ b/.github/workflows/test-mobile-e2e-reusable.yml @@ -52,10 +52,15 @@ permissions: id-token: write contents: read +env: + SPECULOS_IMAGE_TAG: ghcr.io/ledgerhq/speculos:0.9.5 + COINAPPS: ${{ github.workspace }}/coin-apps + jobs: detox-tests-ios: name: "LLM - iOS Detox Tests" runs-on: [m1, ARM64] + if: ${{ !inputs.speculos_tests }} env: NODE_OPTIONS: "--max-old-space-size=7168" LANG: en_US.UTF-8 @@ -89,7 +94,7 @@ jobs: id: detox-build with: path: ${{ github.workspace }}/apps/ledger-live-mobile/ios/build/Build/Products/Release-iphonesimulator - key: ${{ runner.os }}-detox-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock', 'apps/ledger-live-mobile/ios/ledgerlivemobile.xcodeproj/project.pbxproj', 'apps/ledger-live-mobile/detox.config.js') }} + key: ${{ runner.os }}-detox-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock', 'apps/ledger-live-mobile/ios/ledgerlivemobile.xcodeproj/project.pbxproj', 'apps/ledger-live-mobile/detox.config.js', 'apps/ledger-live-mobile/.env.mock') }} accessKey: ${{ env.AWS_ACCESS_KEY_ID }} secretKey: ${{ env.AWS_SECRET_ACCESS_KEY }} sessionToken: ${{ env.AWS_SESSION_TOKEN}} @@ -121,10 +126,21 @@ jobs: - name: Build JS Bundle app for Detox test run if: steps.detox-build.outputs.cache-hit == 'true' run: pnpm mobile e2e:ci -p ios --bundle + - name: Setup Speculos image and Coin Apps + if: ${{ inputs.speculos_tests }} + uses: LedgerHQ/ledger-live/tools/actions/composites/setup-speculos_image@develop + with: + coinapps_path: ${{ env.COINAPPS }} + speculos_tag: ${{ env.SPECULOS_IMAGE_TAG }} + bot_id: ${{ secrets.GH_BOT_APP_ID }} + bot_key: ${{ secrets.GH_BOT_PRIVATE_KEY }} - name: Test iOS app id: detox timeout-minutes: 75 - run: pnpm mobile e2e:ci -p ios -t + run: pnpm mobile e2e:ci -p ios -t $([[ "$INPUT_SPECULOS" == "true" ]] && printf %s '--speculos') + env: + SEED: ${{ secrets.SEED_QAA_B2C }} + INPUT_SPECULOS: ${{ inputs.speculos_tests }} - name: Delete iOS simulator if: ${{ always() && steps.simulator.outputs.id }} run: | @@ -180,8 +196,6 @@ jobs: AVD_CORES: 4 AVD_RAM_SIZE: 4096M AVD_OPTIONS: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - SPECULOS_IMAGE_TAG: ghcr.io/ledgerhq/speculos:0.9.5 - COINAPPS: ${{ github.workspace }}/coin-apps outputs: status: ${{ steps.detox.outcome }} steps: diff --git a/apps/ledger-live-desktop/tests/component/drawer.component.ts b/apps/ledger-live-desktop/tests/component/drawer.component.ts index 5aeb8d1b4527..8a2d0c4eadbd 100644 --- a/apps/ledger-live-desktop/tests/component/drawer.component.ts +++ b/apps/ledger-live-desktop/tests/component/drawer.component.ts @@ -1,6 +1,6 @@ import { Component } from "tests/page/abstractClasses"; import { step } from "tests/misc/reporters/step"; -import { Account } from "tests/enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; export class Drawer extends Component { readonly content = this.page.getByTestId("drawer-content"); diff --git a/apps/ledger-live-desktop/tests/fixtures/common.ts b/apps/ledger-live-desktop/tests/fixtures/common.ts index 18c0c3fe7b83..c8e1ea39e646 100644 --- a/apps/ledger-live-desktop/tests/fixtures/common.ts +++ b/apps/ledger-live-desktop/tests/fixtures/common.ts @@ -11,7 +11,7 @@ import { safeAppendFile } from "tests/utils/fileUtils"; import { launchApp } from "tests/utils/electronUtils"; import { captureArtifacts } from "tests/utils/allureUtils"; import { randomUUID } from "crypto"; -import { AppInfos } from "tests/enum/AppInfos"; +import { AppInfos } from "@ledgerhq/live-common/e2e/enum/AppInfos"; import { lastValueFrom, Observable } from "rxjs"; import { commandCLI } from "tests/utils/cliUtils"; import { registerSpeculosTransport } from "@ledgerhq/live-cli/src/live-common-setup"; diff --git a/apps/ledger-live-desktop/tests/models/Delegate.ts b/apps/ledger-live-desktop/tests/models/Delegate.ts index f4142fb9b65e..60811212792c 100644 --- a/apps/ledger-live-desktop/tests/models/Delegate.ts +++ b/apps/ledger-live-desktop/tests/models/Delegate.ts @@ -1,4 +1,4 @@ -import { Account } from "../enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; export class Delegate { constructor( diff --git a/apps/ledger-live-desktop/tests/models/Swap.ts b/apps/ledger-live-desktop/tests/models/Swap.ts index 8e9affb5cf7e..db010055ff56 100644 --- a/apps/ledger-live-desktop/tests/models/Swap.ts +++ b/apps/ledger-live-desktop/tests/models/Swap.ts @@ -1,7 +1,7 @@ import { Transaction } from "tests/models/Transaction"; -import { Fee } from "tests/enum/Fee"; -import { Account } from "../enum/Account"; -import { Provider, Rate } from "../enum/Swap"; +import { Fee } from "@ledgerhq/live-common/e2e/enum/Fee"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; +import { Provider, Rate } from "@ledgerhq/live-common/e2e/enum/Swap"; export class Swap extends Transaction { provider: Provider; diff --git a/apps/ledger-live-desktop/tests/models/Transaction.ts b/apps/ledger-live-desktop/tests/models/Transaction.ts index 08333b27e952..e66649adc9b1 100644 --- a/apps/ledger-live-desktop/tests/models/Transaction.ts +++ b/apps/ledger-live-desktop/tests/models/Transaction.ts @@ -1,5 +1,5 @@ -import { Fee } from "tests/enum/Fee"; -import { Account } from "../enum/Account"; +import { Fee } from "@ledgerhq/live-common/e2e/enum/Fee"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; export class Transaction { constructor( diff --git a/apps/ledger-live-desktop/tests/page/account.page.ts b/apps/ledger-live-desktop/tests/page/account.page.ts index af0b864f1d30..2bf10051e18e 100644 --- a/apps/ledger-live-desktop/tests/page/account.page.ts +++ b/apps/ledger-live-desktop/tests/page/account.page.ts @@ -1,7 +1,7 @@ import { expect } from "@playwright/test"; import { step } from "tests/misc/reporters/step"; import { AppPage } from "tests/page/abstractClasses"; -import { Account } from "tests/enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; export class AccountPage extends AppPage { readonly settingsButton = this.page.getByTestId("account-settings-button"); diff --git a/apps/ledger-live-desktop/tests/page/accounts.page.ts b/apps/ledger-live-desktop/tests/page/accounts.page.ts index ebfa8cf9c2e8..537e6586aeb5 100644 --- a/apps/ledger-live-desktop/tests/page/accounts.page.ts +++ b/apps/ledger-live-desktop/tests/page/accounts.page.ts @@ -1,7 +1,7 @@ import { expect } from "@playwright/test"; import { step } from "tests/misc/reporters/step"; import { AppPage } from "tests/page/abstractClasses"; -import { Currency } from "../enum/Currency"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; export class AccountsPage extends AppPage { private addAccountButton = this.page.getByTestId("accounts-add-account-button"); diff --git a/apps/ledger-live-desktop/tests/page/drawer/asset.drawer.ts b/apps/ledger-live-desktop/tests/page/drawer/asset.drawer.ts index c3761fb7510f..02343f8dd2ec 100644 --- a/apps/ledger-live-desktop/tests/page/drawer/asset.drawer.ts +++ b/apps/ledger-live-desktop/tests/page/drawer/asset.drawer.ts @@ -1,7 +1,7 @@ import { step } from "tests/misc/reporters/step"; import { Drawer } from "tests/component/drawer.component"; -import { Currency } from "tests/enum/Currency"; -import { Account } from "tests/enum/Account"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; export class AssetDrawer extends Drawer { private assetInput = this.page.getByTestId("select-asset-drawer-search-input"); diff --git a/apps/ledger-live-desktop/tests/page/drawer/delegate.drawer.ts b/apps/ledger-live-desktop/tests/page/drawer/delegate.drawer.ts index bec74710af40..3312d8d8497c 100644 --- a/apps/ledger-live-desktop/tests/page/drawer/delegate.drawer.ts +++ b/apps/ledger-live-desktop/tests/page/drawer/delegate.drawer.ts @@ -1,6 +1,6 @@ import { step } from "tests/misc/reporters/step"; import { Drawer } from "tests/component/drawer.component"; -import { Currency } from "tests/enum/Currency"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; import { Delegate } from "tests/models/Delegate"; import { expect } from "@playwright/test"; import { Transaction } from "tests/models/Transaction"; diff --git a/apps/ledger-live-desktop/tests/page/modal/add.account.modal.ts b/apps/ledger-live-desktop/tests/page/modal/add.account.modal.ts index 241c9bc619c8..b37b8c894ee1 100644 --- a/apps/ledger-live-desktop/tests/page/modal/add.account.modal.ts +++ b/apps/ledger-live-desktop/tests/page/modal/add.account.modal.ts @@ -1,8 +1,8 @@ import { expect } from "@playwright/test"; import { Modal } from "../../component/modal.component"; import { step } from "tests/misc/reporters/step"; -import { Account } from "tests/enum/Account"; -import { Currency } from "tests/enum/Currency"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; export class AddAccountModal extends Modal { private selectAccount = this.page.locator("text=Choose a crypto asset"); // FIXME: I need an id diff --git a/apps/ledger-live-desktop/tests/page/modal/receive.modal.ts b/apps/ledger-live-desktop/tests/page/modal/receive.modal.ts index 10c88bb0694d..afd6f1a40d82 100644 --- a/apps/ledger-live-desktop/tests/page/modal/receive.modal.ts +++ b/apps/ledger-live-desktop/tests/page/modal/receive.modal.ts @@ -1,7 +1,7 @@ import { expect } from "@playwright/test"; import { Modal } from "../../component/modal.component"; import { step } from "tests/misc/reporters/step"; -import { Account } from "tests/enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; export class ReceiveModal extends Modal { private skipDeviceButton = this.page.getByTestId("receive-connect-device-skip-device-button"); diff --git a/apps/ledger-live-desktop/tests/page/speculos.page.ts b/apps/ledger-live-desktop/tests/page/speculos.page.ts index bb64553da851..2c74010c2bfc 100644 --- a/apps/ledger-live-desktop/tests/page/speculos.page.ts +++ b/apps/ledger-live-desktop/tests/page/speculos.page.ts @@ -6,12 +6,12 @@ import { waitFor, containsSubstringInEvent, } from "@ledgerhq/live-common/e2e/speculos"; -import { Account } from "../enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { expect } from "@playwright/test"; import { Transaction } from "tests/models/Transaction"; import { Delegate } from "tests/models/Delegate"; -import { DeviceLabels } from "tests/enum/DeviceLabels"; -import { Currency } from "tests/enum/Currency"; +import { DeviceLabels } from "@ledgerhq/live-common/e2e/enum/DeviceLabels"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; import { Swap } from "tests/models/Swap"; import { extractNumberFromString } from "tests/utils/textParserUtils"; export class SpeculosPage extends AppPage { diff --git a/apps/ledger-live-desktop/tests/page/swap.page.ts b/apps/ledger-live-desktop/tests/page/swap.page.ts index b8332f731432..650f9e3b7531 100644 --- a/apps/ledger-live-desktop/tests/page/swap.page.ts +++ b/apps/ledger-live-desktop/tests/page/swap.page.ts @@ -3,7 +3,7 @@ import { waitFor } from "../utils/waitFor"; import { step } from "tests/misc/reporters/step"; import { ElectronApplication, expect } from "@playwright/test"; import { capitalizeFirstLetter } from "tests/utils/textParserUtils"; -import { Account } from "tests/enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { ChooseAssetDrawer } from "tests/page/drawer/choose.asset.drawer"; export class SwapPage extends AppPage { diff --git a/apps/ledger-live-desktop/tests/specs/speculos/add.account.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/add.account.spec.ts index fcfa988b19bb..187dc09ebfe7 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/add.account.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/add.account.spec.ts @@ -1,5 +1,5 @@ import { test } from "../../fixtures/common"; -import { Currency } from "../../enum/Currency"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/delegate.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/delegate.spec.ts index e6900a7163af..d7258334afb2 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/delegate.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/delegate.spec.ts @@ -1,5 +1,5 @@ import { test } from "../../fixtures/common"; -import { Account } from "../../enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { Delegate } from "../../models/Delegate"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/delete.account.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/delete.account.spec.ts index 85b4c5f39d9d..eaab81c0cde5 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/delete.account.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/delete.account.spec.ts @@ -1,5 +1,5 @@ import { test } from "../../fixtures/common"; -import { Account } from "../../enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; import { commandCLI } from "tests/utils/cliUtils"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/manage.ledgersync.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/manage.ledgersync.spec.ts index 1291396fe02e..abd0ab3ede04 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/manage.ledgersync.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/manage.ledgersync.spec.ts @@ -1,5 +1,5 @@ import { test } from "../../fixtures/common"; -import { AppInfos } from "tests/enum/AppInfos"; +import { AppInfos } from "@ledgerhq/live-common/e2e/enum/AppInfos"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/receive.address.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/receive.address.spec.ts index 5ecf99b5bc6e..6bb844f48edb 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/receive.address.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/receive.address.spec.ts @@ -1,5 +1,5 @@ import { test } from "../../fixtures/common"; -import { Account } from "../../enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; import { commandCLI } from "tests/utils/cliUtils"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/send.tx.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/send.tx.spec.ts index cdb5b54295c9..2f9200d84c51 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/send.tx.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/send.tx.spec.ts @@ -1,6 +1,6 @@ import { test } from "../../fixtures/common"; -import { Account } from "../../enum/Account"; -import { Fee } from "../../enum/Fee"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; +import { Fee } from "@ledgerhq/live-common/e2e/enum/Fee"; import { Transaction } from "../../models/Transaction"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/settings.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/settings.spec.ts index e0887a23093e..d0700b121208 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/settings.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/settings.spec.ts @@ -1,7 +1,7 @@ import { test } from "../../fixtures/common"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; -import { Account } from "tests/enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; test.describe("Settings", () => { test.use({ diff --git a/apps/ledger-live-desktop/tests/specs/speculos/subAccount.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/subAccount.spec.ts index c351fe0aa532..329b8bee73c3 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/subAccount.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/subAccount.spec.ts @@ -1,5 +1,5 @@ import { test } from "../../fixtures/common"; -import { Account } from "../../enum/Account"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "../../utils/customJsonReporter"; diff --git a/apps/ledger-live-desktop/tests/specs/speculos/swap.spec.ts b/apps/ledger-live-desktop/tests/specs/speculos/swap.spec.ts index ba908a500063..4c3aa6088567 100644 --- a/apps/ledger-live-desktop/tests/specs/speculos/swap.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/speculos/swap.spec.ts @@ -1,10 +1,10 @@ import test from "../../fixtures/common"; -import { Account } from "tests/enum/Account"; -import { AppInfos } from "tests/enum/AppInfos"; +import { Account } from "@ledgerhq/live-common/e2e/enum/Account"; +import { AppInfos } from "@ledgerhq/live-common/e2e/enum/AppInfos"; import { setExchangeDependencies } from "@ledgerhq/live-common/e2e/speculos"; -import { Fee } from "tests/enum/Fee"; +import { Fee } from "@ledgerhq/live-common/e2e/enum/Fee"; import { Swap } from "tests/models/Swap"; -import { Provider, Rate } from "tests/enum/Swap"; +import { Provider, Rate } from "@ledgerhq/live-common/e2e/enum/Swap"; import { addTmsLink } from "tests/utils/allureUtils"; import { getDescription } from "tests/utils/customJsonReporter"; import { Application } from "tests/page"; diff --git a/apps/ledger-live-mobile/.env.mock b/apps/ledger-live-mobile/.env.mock index f243d3f1eb60..e5688b9c296e 100644 --- a/apps/ledger-live-mobile/.env.mock +++ b/apps/ledger-live-mobile/.env.mock @@ -1,6 +1,7 @@ APP_NAME="LLmock" MOCK=1 MOCK_COUNTERVALUES=1 +DETOX=1 DISABLE_YELLOW_BOX=1 GOOGLE_SERVICE_INFO_NAME="GoogleService-Info-Testing" MOCK_SCAN_RECIPIENT=bitcoin:3HX3Q4wgYi8nKakxv7kmdCgLWJFrFgcqEt?amount=0.001 diff --git a/apps/ledger-live-mobile/e2e/bridge/client.ts b/apps/ledger-live-mobile/e2e/bridge/client.ts index 84d9312fec7a..3a8586614751 100644 --- a/apps/ledger-live-mobile/e2e/bridge/client.ts +++ b/apps/ledger-live-mobile/e2e/bridge/client.ts @@ -24,7 +24,10 @@ const retryDelay = 500; // Initial retry delay in milliseconds export function init() { const wsPort = LaunchArguments.value()["wsPort"] || "8099"; + const mock = LaunchArguments.value()["mock"]; + log(`[E2E Bridge Client]: wsPort=${wsPort}, mock=${mock}`); + if (mock == "0") setEnv("MOCK", ""); if (ws) { ws.close(); } diff --git a/apps/ledger-live-mobile/e2e/helpers.ts b/apps/ledger-live-mobile/e2e/helpers.ts index 566e16db7022..bdc5d54f1eb3 100644 --- a/apps/ledger-live-mobile/e2e/helpers.ts +++ b/apps/ledger-live-mobile/e2e/helpers.ts @@ -5,7 +5,7 @@ import { findFreePort, close as closeBridge, init as initBridge } from "./bridge import { startSpeculos, stopSpeculos, specs } from "@ledgerhq/live-common/e2e/speculos"; import { SpeculosDevice } from "@ledgerhq/speculos-transport"; import invariant from "invariant"; -import { setEnv } from "@ledgerhq/live-env"; +import { getEnv, setEnv } from "@ledgerhq/live-env"; import { startProxy, closeProxy } from "./bridge/proxy"; const DEFAULT_TIMEOUT = 60000; // 60s !! @@ -121,6 +121,14 @@ export async function getTextOfElement(id: string | RegExp, index = 0) { return (!("elements" in attributes) ? attributes.text : attributes.elements[index].text) || ""; } +export async function getIdOfElement(id: RegExp, index = 0) { + const attributes = await getElementById(id, index).getAttributes(); + return ( + (!("elements" in attributes) ? attributes.identifier : attributes.elements[index].identifier) || + "" + ); +} + /** * Waits for a specified amount of time * /!\ Do not use it to wait for a specific element, use waitFor instead. @@ -152,6 +160,7 @@ export async function launchApp() { wsPort: port, detoxURLBlacklistRegex: '\\(".*sdk.*.braze.*",".*.googleapis.com/.*",".*clients3.google.com.*"\\)', + mock: getEnv("MOCK") ? getEnv("MOCK") : "0", }, languageAndLocale: { language: "en-US", @@ -171,11 +180,11 @@ export async function launchSpeculos(appName: string, proxyPort: number) { } const speculosPort = portCounter++; const speculosPidOffset = - (speculosPort - BASE_PORT) * 1000 + parseInt(process.env.TEST_WORKER_INDEX || "0") * 100; + (speculosPort - BASE_PORT) * 1000 + parseInt(process.env.JEST_WORKER_ID || "0") * 100; setEnv("SPECULOS_PID_OFFSET", speculosPidOffset); const testName = expect.getState().testPath || "unknown"; - const speculosDevice = await startSpeculos(testName, specs[appName]); + const speculosDevice = await startSpeculos(testName, specs[appName.replace(/ /g, "_")]); invariant(speculosDevice, "[E2E Setup] Speculos not started"); const speculosApiPort = speculosDevice.ports.apiPort; diff --git a/apps/ledger-live-mobile/e2e/jest.globalTeardown.ts b/apps/ledger-live-mobile/e2e/jest.globalTeardown.ts index 51b579b0e060..6843276b5904 100644 --- a/apps/ledger-live-mobile/e2e/jest.globalTeardown.ts +++ b/apps/ledger-live-mobile/e2e/jest.globalTeardown.ts @@ -1,10 +1,9 @@ const detoxGlobalTeardown = require("detox/runners/jest/globalTeardown"); import { promises as fs } from "fs"; -import { getEnvs, getFlags } from "./bridge/server"; +import { getEnvs, getFlags, loadConfig } from "./bridge/server"; import { formatFlagsData, formatEnvData } from "@ledgerhq/live-common/e2e/index"; -import { launchApp } from "./helpers"; +import { launchApp, waitForElementById } from "./helpers"; import detox from "detox/internals"; -import { Application } from "./page"; import { close as closeBridge } from "./bridge/server"; const environmentFilePath = "artifacts/environment.properties"; @@ -15,8 +14,8 @@ export default async () => { try { await initDetox(); await launchApp(); - const app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse"); - await app.portfolio.waitForPortfolioPageToLoad(); + await loadConfig("1AccountBTC1AccountETHReadOnlyFalse", true); + await waitForElementById("settings-icon", 120000); const flagsData = formatFlagsData(JSON.parse(await getFlags())); const envsData = formatEnvData(JSON.parse(await getEnvs())); await fs.appendFile(environmentFilePath, flagsData + envsData); 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 f05bc02ef832..1c7e0f5d5729 100644 --- a/apps/ledger-live-mobile/e2e/page/accounts/account.page.ts +++ b/apps/ledger-live-mobile/e2e/page/accounts/account.page.ts @@ -1,43 +1,43 @@ +import { getElementById, getTextOfElement, scrollToId, tapByElement } from "../../helpers"; import { expect } from "detox"; -import { - currencyParam, - openDeeplink, - waitForElementById, - getElementById, - tapByElement, -} from "../../helpers"; - -const baseLink = "account"; +import jestExpect from "expect"; export default class AccountPage { - accountSettingsButton = () => getElementById("accounts-settings"); - assetBalance = () => getElementById("asset-graph-balance"); - accountTitleId = (assetName: string) => `accounts-title-${assetName}`; - accountAssetId = (assetName: string) => `account-assets-${assetName}`; - - async waitForAccountPageToLoad(assetName: string) { - await waitForElementById(this.accountTitleId(assetName)); - } + accountGraph = (accountId: string) => getElementById(`account-graph-${accountId}`); + accountBalance = (accountId: string) => getElementById(`account-balance-${accountId}`); + accountSettingsButton = () => getElementById("account-settings-button"); + accountAdvancedLogRow = () => getElementById("account-advanced-log-row"); + operationHistorySectionId = (accountId: string) => `operations-history-${accountId}`; + accountScreenScrollView = "account-screen-scrollView"; + accountAdvancedLogsId = "account-advanced-logs"; - async expectAccountBalanceVisible() { - await expect(this.assetBalance()).toBeVisible(); + async openAccountSettings() { + await tapByElement(this.accountSettingsButton()); } - async expectAccountBalance(expectedBalance: string) { - await expect(this.assetBalance()).toHaveText(expectedBalance); + async openAccountAdvancedLogs() { + await tapByElement(this.accountAdvancedLogRow()); } - async waitForAccountAssetsToLoad(assetName: string) { - await waitForElementById(this.accountTitleId(assetName)); - await waitForElementById(this.accountAssetId(assetName)); + @Step("Expect operation history to be visible") + async expectOperationHistoryVisible(accountId: string) { + const id = this.operationHistorySectionId(accountId); + await scrollToId(id, this.accountScreenScrollView); + await expect(getElementById(id)).toBeVisible(); } - async openViaDeeplink(currencyLong?: string) { - const link = currencyLong ? baseLink + currencyParam + currencyLong : baseLink; - await openDeeplink(link); + @Step("Expect account balance to be visible") + async expectAccountBalanceVisible(accountId: string) { + await expect(this.accountGraph(accountId)).toBeVisible(); + await expect(this.accountBalance(accountId)).toBeVisible(); } - async openAccountSettings() { - await tapByElement(this.accountSettingsButton()); + @Step("Expect address index") + async expectAddressIndex(indexNumber: number) { + await this.openAccountSettings(); + await this.openAccountAdvancedLogs(); + const advancedLogsText = await getTextOfElement(this.accountAdvancedLogsId); + const advancedLogsJson = advancedLogsText ? JSON.parse(advancedLogsText) : null; + jestExpect(advancedLogsJson).toHaveProperty("index", indexNumber); } } diff --git a/apps/ledger-live-mobile/e2e/page/accounts/addAccount.drawer.ts b/apps/ledger-live-mobile/e2e/page/accounts/addAccount.drawer.ts index ccc16068d54c..4ed66448b778 100644 --- a/apps/ledger-live-mobile/e2e/page/accounts/addAccount.drawer.ts +++ b/apps/ledger-live-mobile/e2e/page/accounts/addAccount.drawer.ts @@ -1,18 +1,32 @@ import { expect } from "detox"; -import { getElementById, openDeeplink, tapById, waitForElementById } from "../../helpers"; -import { capitalize } from "../../models/currencies"; +import { + getElementById, + getIdOfElement, + openDeeplink, + scrollToId, + tapById, + waitForElementById, +} from "../../helpers"; +import { getEnv } from "@ledgerhq/live-env"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; const baseLink = "add-account"; +const isMock = getEnv("MOCK"); export default class AddAccountDrawer { - accountCardId = (id: string) => getElementById(`account-card-${id}`); - accountId = (currency: string, index: number) => `mock:1:${currency}:MOCK_${currency}_${index}:`; - accountTitleId = (accountName: string) => getElementById(`test-id-account-${accountName}`); + deselectAllButtonId = "add-accounts-deselect-all"; + accountCardRegExp = (id = ".*") => new RegExp(`account-card-${id}`); + accountCard = (id: string) => getElementById(this.accountCardRegExp(id)); + accountId = (currency: string, index: number) => + isMock ? `mock:1:${currency}:MOCK_${currency}_${index}:` : `js:2:${currency}:.*`; + accountTitleId = (accountName: string, index: number) => + getElementById(`test-id-account-${accountName}`, index); modalButtonId = "add-accounts-modal-add-button"; currencyRow = (currencyId: string) => `currency-row-${currencyId}`; continueButtonId = "add-accounts-continue-button"; succesCtaId = "add-accounts-success-cta"; + @Step("Open add account via deeplink") async openViaDeeplink() { await openDeeplink(baseLink); } @@ -22,29 +36,49 @@ export default class AddAccountDrawer { await tapById(this.modalButtonId); } + @Step("Select currency") async selectCurrency(currencyId: string) { const id = this.currencyRow(currencyId); - await waitForElementById(id); + await scrollToId(id); await tapById(id); } + @Step("Start accounts discovery") async startAccountsDiscovery() { - await waitForElementById(this.continueButtonId); + await waitForElementById(this.continueButtonId, 120000); } - async expectAccountDiscovery(currency: string, index: number) { - const accountName = `${capitalize(currency)} ${index + 1}`; - await expect(this.accountCardId(this.accountId(currency, index))).toBeVisible(); - await expect(this.accountTitleId(accountName)).toHaveText(accountName); + @Step("Expect account discovered") + async expectAccountDiscovery(currencyName: string, currencyId: string, index = 0) { + const accountName = `${currencyName} ${index + 1}`; + await expect(this.accountCard(this.accountId(currencyId, index))).toBeVisible(); + await expect(this.accountTitleId(accountName, index)).toHaveText(accountName); } + @Step("Finish account discovery") async finishAccountsDiscovery() { await waitForElementById(this.continueButtonId); await tapById(this.continueButtonId); } + @Step("Close add account success screen") async tapSuccessCta() { await waitForElementById(this.succesCtaId); await tapById(this.succesCtaId); } + + @Step("Add only first discovered account") + async addFirstAccount(currency: Currency) { + await this.startAccountsDiscovery(); + await this.expectAccountDiscovery(currency.name, currency.currencyId); + await tapById(this.deselectAllButtonId); + await tapById(this.accountCardRegExp(), 0); + const accountId = (await getIdOfElement(this.accountCardRegExp(), 0)).replace( + /^account-card-/, + "", + ); + await this.finishAccountsDiscovery(); + await this.tapSuccessCta(); + return accountId; + } } diff --git a/apps/ledger-live-mobile/e2e/page/accounts/assetAccounts.page.ts b/apps/ledger-live-mobile/e2e/page/accounts/assetAccounts.page.ts new file mode 100644 index 000000000000..2bf8992d5ccb --- /dev/null +++ b/apps/ledger-live-mobile/e2e/page/accounts/assetAccounts.page.ts @@ -0,0 +1,49 @@ +import { expect } from "detox"; +import { + currencyParam, + openDeeplink, + waitForElementById, + getElementById, + scrollToId, + tapById, +} from "../../helpers"; + +const baseLink = "account"; + +export default class AssetAccountsPage { + assetBalance = () => getElementById("asset-graph-balance"); + titleId = (assetName: string) => `accounts-title-${assetName}`; + accountAssetId = (assetName: string) => `account-assets-${assetName}`; + accountRowId = (accountId: string) => `account-row-${accountId}`; + accountNameRegExp = /account-row-name-.*/; + + @Step("Wait for asset page to load") + async waitForAccountPageToLoad(assetName: string) { + await waitForElementById(this.titleId(assetName.toLowerCase())); + } + + @Step("Expect asset balance to be visible") + async expectAccountsBalanceVisible() { + await expect(this.assetBalance()).toBeVisible(); + } + + async expectAccountsBalance(expectedBalance: string) { + await expect(this.assetBalance()).toHaveText(expectedBalance); + } + + async waitForAccountAssetsToLoad(assetName: string) { + await waitForElementById(this.titleId(assetName)); + await waitForElementById(this.accountAssetId(assetName)); + } + + async openViaDeeplink(currencyLong?: string) { + const link = currencyLong ? baseLink + currencyParam + currencyLong : baseLink; + await openDeeplink(link); + } + + @Step("Go to the account") + async goToAccount(accountId: string) { + await scrollToId(this.accountNameRegExp); + await tapById(this.accountRowId(accountId)); + } +} diff --git a/apps/ledger-live-mobile/e2e/page/common.page.ts b/apps/ledger-live-mobile/e2e/page/common.page.ts index f9593ac177e9..89ef37a2710c 100644 --- a/apps/ledger-live-mobile/e2e/page/common.page.ts +++ b/apps/ledger-live-mobile/e2e/page/common.page.ts @@ -27,6 +27,7 @@ export default class CommonPage { scannedDeviceRow = (id: string) => `device-scanned-${id}`; pluggedDeviceRow = (nano: DeviceUSB) => `device-item-usb|${JSON.stringify(nano)}`; + @Step("Perform search") async performSearch(text: string) { await waitForElementById(this.searchBarId); await typeTextByElement(this.searchBar(), text, false); @@ -83,8 +84,8 @@ export default class CommonPage { return proxyPort; } - async removeSpeculos(proxyPort: number) { + async removeSpeculos(proxyPort?: number) { await deleteSpeculos(proxyPort); - await bridge.removeKnownSpeculos(`${proxyAddress}:${proxyPort}`); + proxyPort && (await bridge.removeKnownSpeculos(`${proxyAddress}:${proxyPort}`)); } } diff --git a/apps/ledger-live-mobile/e2e/page/index.ts b/apps/ledger-live-mobile/e2e/page/index.ts index 67b420e9d432..2c61e9434d3d 100644 --- a/apps/ledger-live-mobile/e2e/page/index.ts +++ b/apps/ledger-live-mobile/e2e/page/index.ts @@ -1,3 +1,4 @@ +import AssetAccountsPage from "./accounts/assetAccounts.page"; import AccountPage from "./accounts/account.page"; import AccountsPage from "./accounts/accounts.page"; import AddAccountDrawer from "./accounts/addAccount.drawer"; @@ -28,8 +29,17 @@ import WalletTabNavigatorPage from "./wallet/walletTabNavigator.page"; import type { Account } from "@ledgerhq/types-live"; import { DeviceLike } from "~/reducers/types"; import { loadAccounts, loadBleState, loadConfig } from "../bridge/server"; +import { AppInfos } from "@ledgerhq/live-common/e2e/enum/AppInfos"; + +type ApplicationOptions = { + speculosApp?: AppInfos; + userdata?: string; + knownDevices?: DeviceLike[]; + testAccounts?: Account[]; +}; export class Application { + public assetAccountsPage = new AssetAccountsPage(); public account = new AccountPage(); public accounts = new AccountsPage(); public addAccount = new AddAccountDrawer(); @@ -57,11 +67,12 @@ export class Application { public transfertMenu = new TransfertMenuDrawer(); public walletTabNavigator = new WalletTabNavigatorPage(); - static async init(userdata?: string, knownDevices?: DeviceLike[], testAccounts?: Account[]) { + static async init({ speculosApp, userdata, knownDevices, testAccounts }: ApplicationOptions) { const app = new Application(); - if (userdata) await loadConfig(userdata, true); - if (knownDevices) await loadBleState({ knownDevices: knownDevices }); - if (testAccounts) await loadAccounts(testAccounts); + userdata && (await loadConfig(userdata, true)); + knownDevices && (await loadBleState({ knownDevices })); + testAccounts && (await loadAccounts(testAccounts)); + speculosApp && (await app.common.addSpeculos(speculosApp.name)); return app; } diff --git a/apps/ledger-live-mobile/e2e/setup.ts b/apps/ledger-live-mobile/e2e/setup.ts index 1f760136968f..92575443871a 100644 --- a/apps/ledger-live-mobile/e2e/setup.ts +++ b/apps/ledger-live-mobile/e2e/setup.ts @@ -11,6 +11,7 @@ import { setEnv } from "@ledgerhq/live-env"; const currentDate = new Date(); const date = format(currentDate, "MM-dd"); const directoryPath = `artifacts/${date}_LLM`; +setEnv("MOCK", process.env.MOCK == "0" ? "" : "1"); beforeAll( async () => { diff --git a/apps/ledger-live-mobile/e2e/specs/addAccounts/addAccount.spec.ts b/apps/ledger-live-mobile/e2e/specs/addAccounts/addAccount.spec.ts index 5c77a1314f19..da2d4e8f9d23 100644 --- a/apps/ledger-live-mobile/e2e/specs/addAccounts/addAccount.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/addAccounts/addAccount.spec.ts @@ -1,6 +1,7 @@ import { knownDevices } from "../../models/devices"; import DeviceAction from "../../models/DeviceAction"; import { Application } from "../../page"; +import { capitalize } from "../../models/currencies"; let app: Application; let deviceAction: DeviceAction; @@ -11,7 +12,10 @@ const knownDevice = knownDevices.nanoX; describe("Add account from modal", () => { beforeAll(async () => { - app = await Application.init("onboardingcompleted", [knownDevice]); + app = await Application.init({ + userdata: "onboardingcompleted", + knownDevices: [knownDevice], + }); deviceAction = new DeviceAction(knownDevice); await app.portfolio.waitForPortfolioPageToLoad(); @@ -29,14 +33,14 @@ describe("Add account from modal", () => { await deviceAction.selectMockDevice(); await deviceAction.openApp(); await app.addAccount.startAccountsDiscovery(); - await app.addAccount.expectAccountDiscovery(testedCurrency, 1); + await app.addAccount.expectAccountDiscovery(capitalize(testedCurrency), testedCurrency, 0); await app.addAccount.finishAccountsDiscovery(); await app.addAccount.tapSuccessCta(); }); $TmsLink("B2CQA-101"); it("displays Bitcoin accounts page summary", async () => { - await app.account.waitForAccountPageToLoad(testedCurrency); - await app.account.expectAccountBalance(expectedBalance); + await app.assetAccountsPage.waitForAccountPageToLoad(testedCurrency); + await app.assetAccountsPage.expectAccountsBalance(expectedBalance); }); }); diff --git a/apps/ledger-live-mobile/e2e/specs/deeplinks.spec.ts b/apps/ledger-live-mobile/e2e/specs/deeplinks.spec.ts index 9fb095c879b6..0bb233524466 100644 --- a/apps/ledger-live-mobile/e2e/specs/deeplinks.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/deeplinks.spec.ts @@ -11,7 +11,10 @@ const bobaLong = "boba"; $TmsLink("B2CQA-1837"); describe("DeepLinks Tests", () => { beforeAll(async () => { - app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse", [knownDevices.nanoX]); + app = await Application.init({ + userdata: "1AccountBTC1AccountETHReadOnlyFalse", + knownDevices: [knownDevices.nanoX], + }); await app.portfolio.waitForPortfolioPageToLoad(); }); @@ -21,7 +24,7 @@ describe("DeepLinks Tests", () => { }); it("should open Account page", async () => { - await app.account.openViaDeeplink(); + await app.assetAccountsPage.openViaDeeplink(); await app.accounts.waitForAccountsPageToLoad(); }); @@ -31,13 +34,13 @@ describe("DeepLinks Tests", () => { }); it("should open ETH Account Asset page when given currency param", async () => { - await app.account.openViaDeeplink(ethereumLong); - await app.account.waitForAccountAssetsToLoad(ethereumLong); + await app.assetAccountsPage.openViaDeeplink(ethereumLong); + await app.assetAccountsPage.waitForAccountAssetsToLoad(ethereumLong); }); it("should open BTC Account Asset page when given currency param", async () => { - await app.account.openViaDeeplink(bitcoinLong); - await app.account.waitForAccountAssetsToLoad(bitcoinLong); + await app.assetAccountsPage.openViaDeeplink(bitcoinLong); + await app.assetAccountsPage.waitForAccountAssetsToLoad(bitcoinLong); }); it("should open Custom Lock Screen page", async () => { diff --git a/apps/ledger-live-mobile/e2e/specs/delegate/cosmos.spec.ts b/apps/ledger-live-mobile/e2e/specs/delegate/cosmos.spec.ts index 9cbd8ed1d96b..38d0872c75bb 100644 --- a/apps/ledger-live-mobile/e2e/specs/delegate/cosmos.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/delegate/cosmos.spec.ts @@ -20,7 +20,11 @@ const knownDevice = knownDevices.nanoX; describe("Cosmos delegate flow", () => { beforeAll(async () => { - app = await Application.init("onboardingcompleted", [knownDevice], [testAccount]); + app = await Application.init({ + userdata: "onboardingcompleted", + knownDevices: [knownDevice], + testAccounts: [testAccount], + }); deviceAction = new DeviceAction(knownDevice); await app.portfolio.waitForPortfolioPageToLoad(); diff --git a/apps/ledger-live-mobile/e2e/specs/languageChange.spec.ts b/apps/ledger-live-mobile/e2e/specs/languageChange.spec.ts index b73d50486e09..b3f70435fe50 100644 --- a/apps/ledger-live-mobile/e2e/specs/languageChange.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/languageChange.spec.ts @@ -26,7 +26,7 @@ const verifyLanguageCanBeChanged = (l10n: { lang: string; localization: string } $TmsLink("B2CQA-2344"); describe("Change Language", () => { beforeAll(async () => { - app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse"); + app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" }); await app.portfolio.waitForPortfolioPageToLoad(); }); diff --git a/apps/ledger-live-mobile/e2e/specs/manager.spec.ts b/apps/ledger-live-mobile/e2e/specs/manager.spec.ts index aa2136228c24..c250a9854992 100644 --- a/apps/ledger-live-mobile/e2e/specs/manager.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/manager.spec.ts @@ -12,7 +12,7 @@ const knownDevice = knownDevices.nanoX; describe("Test My Ledger", () => { beforeAll(async () => { - app = await Application.init("onboardingcompleted"); + app = await Application.init({ userdata: "onboardingcompleted" }); deviceAction = new DeviceAction(knownDevice); await app.portfolio.waitForPortfolioPageToLoad(); diff --git a/apps/ledger-live-mobile/e2e/specs/market.spec.ts b/apps/ledger-live-mobile/e2e/specs/market.spec.ts index e98d91bfd164..6fdece52b615 100644 --- a/apps/ledger-live-mobile/e2e/specs/market.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/market.spec.ts @@ -5,7 +5,7 @@ const asset = "Ethereum (ETH)"; describe("Market page for user with no device", () => { beforeAll(async () => { - app = await Application.init("1accountEth"); + app = await Application.init({ userdata: "1accountEth" }); await app.portfolio.waitForPortfolioPageToLoad(); }); diff --git a/apps/ledger-live-mobile/e2e/specs/nftGallery.spec.ts b/apps/ledger-live-mobile/e2e/specs/nftGallery.spec.ts index e54c94890a97..e30d7ee847f3 100644 --- a/apps/ledger-live-mobile/e2e/specs/nftGallery.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/nftGallery.spec.ts @@ -7,7 +7,7 @@ const accountCurrency = "ethereum"; // To-Do Fix NFT not available in account describe.skip("NFT Gallery screen", () => { beforeAll(async () => { - app = await Application.init("1Account1NFTNotSpam"); + app = await Application.init({ userdata: "1Account1NFTNotSpam" }); await app.portfolio.waitForPortfolioPageToLoad(); await app.nftGallery.openViaDeeplink(); diff --git a/apps/ledger-live-mobile/e2e/specs/password.spec.ts b/apps/ledger-live-mobile/e2e/specs/password.spec.ts index cce8b2d78e7d..01a35a9d9aeb 100644 --- a/apps/ledger-live-mobile/e2e/specs/password.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/password.spec.ts @@ -7,7 +7,7 @@ const CORRECT_PASSWORD = "passWORD$123!"; describe("Password Lock Screen", () => { beforeAll(async () => { - app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse"); + app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" }); await app.portfolio.waitForPortfolioPageToLoad(); }); diff --git a/apps/ledger-live-mobile/e2e/specs/receive/currencies.spec.ts b/apps/ledger-live-mobile/e2e/specs/receive/currencies.spec.ts index 3a163c142643..edd1ad3e23fc 100644 --- a/apps/ledger-live-mobile/e2e/specs/receive/currencies.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/receive/currencies.spec.ts @@ -12,7 +12,10 @@ $TmsLink("B2CQA-651"); $TmsLink("B2CQA-1854"); describe("Receive different currency", () => { beforeAll(async () => { - app = await Application.init("onboardingcompleted", [knownDevice]); + app = await Application.init({ + userdata: "onboardingcompleted", + knownDevices: [knownDevice], + }); deviceAction = new DeviceAction(knownDevice); await app.portfolio.waitForPortfolioPageToLoad(); diff --git a/apps/ledger-live-mobile/e2e/specs/receive/receiveFlow.spec.ts b/apps/ledger-live-mobile/e2e/specs/receive/receiveFlow.spec.ts index d53df9941973..5c2f4d78ce15 100644 --- a/apps/ledger-live-mobile/e2e/specs/receive/receiveFlow.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/receive/receiveFlow.spec.ts @@ -10,7 +10,10 @@ const knownDevice = knownDevices.nanoX; describe("Receive Flow", () => { beforeAll(async () => { - app = await Application.init("EthAccountXrpAccountReadOnlyFalse", [knownDevice]); + app = await Application.init({ + userdata: "EthAccountXrpAccountReadOnlyFalse", + knownDevices: [knownDevice], + }); deviceAction = new DeviceAction(knownDevice); await app.portfolio.waitForPortfolioPageToLoad(); diff --git a/apps/ledger-live-mobile/e2e/specs/send/currencies.spec.ts b/apps/ledger-live-mobile/e2e/specs/send/currencies.spec.ts index 557f6929096f..33e16cf26f3e 100644 --- a/apps/ledger-live-mobile/e2e/specs/send/currencies.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/send/currencies.spec.ts @@ -35,7 +35,11 @@ const knownDevice = knownDevices.nanoX; $TmsLink("B2CQA-1823"); describe("Send flow", () => { beforeAll(async () => { - app = await Application.init("onboardingcompleted", [knownDevice], testAccounts); + app = await Application.init({ + userdata: "onboardingcompleted", + knownDevices: [knownDevice], + testAccounts: testAccounts, + }); deviceAction = new DeviceAction(knownDevice); await app.portfolio.waitForPortfolioPageToLoad(); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount.spec.ts deleted file mode 100644 index 4465e86e6826..000000000000 --- a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Application } from "../../page"; - -let app: Application; - -const currencies = [ - { currency: "bitcoin", nanoApp: "Bitcoin", tmsLink: "B2CQA-101" }, - { currency: "ethereum", nanoApp: "Ethereum", tmsLink: "B2CQA-102" }, -]; - -describe("Add accounts", () => { - beforeAll(async () => { - app = await Application.init("onboardingcompleted"); - await app.portfolio.waitForPortfolioPageToLoad(); - }); - - currencies.forEach(({ currency, nanoApp, tmsLink }) => { - let deviceNumber: number; - - $TmsLink(tmsLink); - it(`${currency}: add accounts`, async () => { - await app.addAccount.openViaDeeplink(); - await app.addAccount.selectCurrency(currency); - - deviceNumber = await app.common.addSpeculos(nanoApp); - - await app.addAccount.startAccountsDiscovery(); - await app.addAccount.expectAccountDiscovery(currency, 1); - await app.addAccount.finishAccountsDiscovery(); - await app.addAccount.tapSuccessCta(); - await app.account.waitForAccountPageToLoad(currency); - await app.account.expectAccountBalanceVisible(); - }); - - afterEach(async () => { - await app.common.removeSpeculos(deviceNumber); - }); - }); -}); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccount.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccount.ts new file mode 100644 index 000000000000..539fe2b199c7 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccount.ts @@ -0,0 +1,35 @@ +import { Application } from "../../../page"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +export async function runAddAccountTest(currency: Currency, tmsLink: string) { + let app: Application; + + describe(`Add accounts - ${currency.name}`, () => { + beforeAll(async () => { + app = await Application.init({ + userdata: "onboardingcompleted", + speculosApp: currency.speculosApp, + }); + await app.portfolio.waitForPortfolioPageToLoad(); + }); + + $TmsLink(tmsLink); + it(`Perform an add account`, async () => { + await app.addAccount.openViaDeeplink(); + await app.common.performSearch(currency.name); + await app.addAccount.selectCurrency(currency.currencyId); + + const accountId = await app.addAccount.addFirstAccount(currency); + await app.assetAccountsPage.waitForAccountPageToLoad(currency.name); + await app.assetAccountsPage.expectAccountsBalanceVisible(); + await app.assetAccountsPage.goToAccount(accountId); + await app.account.expectAccountBalanceVisible(accountId); + await app.account.expectOperationHistoryVisible(accountId); + await app.account.expectAddressIndex(0); + }); + + afterAll(async () => { + await app.common.removeSpeculos(); + }); + }); +} diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountADA.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountADA.spec.ts new file mode 100644 index 000000000000..87cb6f45ef9e --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountADA.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.ADA, "B2CQA-2500, B2CQA-2650, B2CQA-2678"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountALGO.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountALGO.spec.ts new file mode 100644 index 000000000000..a3933d2af648 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountALGO.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.ALGO, "B2CQA-2497, B2CQA-2653, B2CQA-2681"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountATOM.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountATOM.spec.ts new file mode 100644 index 000000000000..314443b0f41d --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountATOM.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.ATOM, "B2CQA-2501, B2CQA-2654, B2CQA-2682"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountBCH.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountBCH.spec.ts new file mode 100644 index 000000000000..cfa248cea620 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountBCH.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.BCH, "B2CQA-2498, B2CQA-2652, B2CQA-2680"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountBTC.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountBTC.spec.ts new file mode 100644 index 000000000000..a023f24482d4 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountBTC.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.BTC, "B2CQA-2499, B2CQA-2644, B2CQA-2672, B2CQA-786"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountDOT.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountDOT.spec.ts new file mode 100644 index 000000000000..fedd5ccf18d7 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountDOT.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.DOT, "B2CQA-2504, B2CQA-2648, B2CQA-2676"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountETC.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountETC.spec.ts new file mode 100644 index 000000000000..801794424158 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountETC.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.ETC, "B2CQA-2502, B2CQA-2646, B2CQA-2674"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountETH.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountETH.spec.ts new file mode 100644 index 000000000000..225cc83eec46 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountETH.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.ETH, "B2CQA-2503, B2CQA-2645, B2CQA-26736"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountSOL.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountSOL.spec.ts new file mode 100644 index 000000000000..42eb44faeff6 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountSOL.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.SOL, "B2CQA-2642, B2CQA-2656, B2CQA-2684"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountTON.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountTON.spec.ts new file mode 100644 index 000000000000..28b01f50f71c --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountTON.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.TON, "B2CQA-2643, B2CQA-2657, B2CQA-2685"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountTRX.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountTRX.spec.ts new file mode 100644 index 000000000000..1310e7efadd8 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountTRX.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.TRX, "B2CQA-2508, B2CQA-2649, B2CQA-2677"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXLM.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXLM.spec.ts new file mode 100644 index 000000000000..42a0b7d7002b --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXLM.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.XLM, "B2CQA-2506, B2CQA-2651, B2CQA-2679"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXRP.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXRP.spec.ts new file mode 100644 index 000000000000..1f6df1119d48 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXRP.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.XRP, "B2CQA-2505, B2CQA-2647, B2CQA-2675"); diff --git a/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXTZ.spec.ts b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXTZ.spec.ts new file mode 100644 index 000000000000..bce641c496b6 --- /dev/null +++ b/apps/ledger-live-mobile/e2e/specs/speculos/addAccount/AddAccountXTZ.spec.ts @@ -0,0 +1,4 @@ +import { runAddAccountTest } from "./AddAccount"; +import { Currency } from "@ledgerhq/live-common/e2e/enum/Currency"; + +runAddAccountTest(Currency.XTZ, "B2CQA-2507, B2CQA-2655, B2CQA-2683"); diff --git a/apps/ledger-live-mobile/e2e/specs/swap/dexSwap.spec.ts b/apps/ledger-live-mobile/e2e/specs/swap/dexSwap.spec.ts index e0766bbddd88..7b6498feaf13 100644 --- a/apps/ledger-live-mobile/e2e/specs/swap/dexSwap.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/swap/dexSwap.spec.ts @@ -4,7 +4,7 @@ let app: Application; describe("DEX Swap", () => { beforeAll(async () => { - app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse"); + app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" }); await app.portfolio.waitForPortfolioPageToLoad(); await app.swap.openViaDeeplink(); diff --git a/apps/ledger-live-mobile/e2e/specs/swap/swap.spec.ts b/apps/ledger-live-mobile/e2e/specs/swap/swap.spec.ts index f3a75867e7a1..000658e9f72d 100644 --- a/apps/ledger-live-mobile/e2e/specs/swap/swap.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/swap/swap.spec.ts @@ -4,7 +4,7 @@ let app: Application; describe("Swap", () => { beforeAll(async () => { - app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse"); + app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" }); await app.portfolio.waitForPortfolioPageToLoad(); }); diff --git a/apps/ledger-live-mobile/e2e/specs/unknown-currency-resilience.spec.ts b/apps/ledger-live-mobile/e2e/specs/unknown-currency-resilience.spec.ts index dc5a88431fb9..382dd923f7b5 100644 --- a/apps/ledger-live-mobile/e2e/specs/unknown-currency-resilience.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/unknown-currency-resilience.spec.ts @@ -22,7 +22,7 @@ describe("Portfolio to load with unknown currency data in accounts", () => { { data: badAccount2, version: 0 }, ]); - app = await Application.init("onboardingcompleted"); + app = await Application.init({ userdata: "onboardingcompleted" }); }); it("opens to empty state", async () => { diff --git a/apps/ledger-live-mobile/e2e/specs/wallet-api.spec.ts b/apps/ledger-live-mobile/e2e/specs/wallet-api.spec.ts index ad2c9e9ba93b..fb4b1d3ae642 100644 --- a/apps/ledger-live-mobile/e2e/specs/wallet-api.spec.ts +++ b/apps/ledger-live-mobile/e2e/specs/wallet-api.spec.ts @@ -4,7 +4,7 @@ let app: Application; describe("Wallet API methods", () => { beforeAll(async () => { - app = await Application.init("1AccountBTC1AccountETHReadOnlyFalse"); + app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" }); await app.dummyWalletApp.startApp(); await app.portfolio.waitForPortfolioPageToLoad(); diff --git a/apps/ledger-live-mobile/e2e/tsconfig.test.json b/apps/ledger-live-mobile/e2e/tsconfig.test.json index 2f10c52d6d80..df42095480e2 100644 --- a/apps/ledger-live-mobile/e2e/tsconfig.test.json +++ b/apps/ledger-live-mobile/e2e/tsconfig.test.json @@ -1,6 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "allowJs": true + "allowJs": true, + "experimentalDecorators": true } } diff --git a/apps/ledger-live-mobile/package.json b/apps/ledger-live-mobile/package.json index 31a39e855085..2f2251ee3f80 100644 --- a/apps/ledger-live-mobile/package.json +++ b/apps/ledger-live-mobile/package.json @@ -19,8 +19,8 @@ "gen-metafile": "zx ./scripts/gen-metafile.mjs", "e2e:build": "pnpm detox build", "e2e:ci": "zx ./scripts/e2e-ci.mjs", - "e2e:test": "pnpm detox test", - "e2e:test:speculos": "pnpm detox test --testMatch $(pwd)/e2e/specs/speculos/**/*.spec.ts", + "e2e:test": "export MOCK=1 && pnpm detox test", + "e2e:test:speculos": "export MOCK=0 && pnpm detox test --testMatch $(pwd)/e2e/specs/speculos/**/**/*.spec.ts", "prebeta": "bundle install", "debug:detox": "pnpm detox test -c ios.manual currencies.spec.ts", "ios:staging": "ENVFILE=.env.ios.staging react-native run-ios --mode Staging", diff --git a/apps/ledger-live-mobile/src/components/AccountGraphCard.tsx b/apps/ledger-live-mobile/src/components/AccountGraphCard.tsx index 588384f494f2..23adfaa331c4 100644 --- a/apps/ledger-live-mobile/src/components/AccountGraphCard.tsx +++ b/apps/ledger-live-mobile/src/components/AccountGraphCard.tsx @@ -258,6 +258,7 @@ const GraphCardHeader = ({ event="SwitchAccountCurrency" eventProperties={{ useCounterValue: shouldUseCounterValue }} onPress={countervalueAvailable ? onSwitchAccountCurrency : undefined} + testID={`account-graph-${account.id}`} > @@ -273,7 +274,13 @@ const GraphCardHeader = ({ - + {typeof items[1]?.value === "number" ? ( ) : ( diff --git a/apps/ledger-live-mobile/src/components/AccountRowLayout.tsx b/apps/ledger-live-mobile/src/components/AccountRowLayout.tsx index 4b3e6b1391ab..01d5efd5ff16 100644 --- a/apps/ledger-live-mobile/src/components/AccountRowLayout.tsx +++ b/apps/ledger-live-mobile/src/components/AccountRowLayout.tsx @@ -14,6 +14,7 @@ type Props = { currencyUnit?: Unit; countervalueChange?: ValueChange; name: string; + id: string; parentAccountName?: string; tag?: string | null | boolean; onPress?: TouchableOpacityProps["onPress"]; @@ -29,6 +30,7 @@ const AccountRowLayout = ({ currency, currencyUnit, name, + id, parentAccountName, onPress, topLink, @@ -39,7 +41,7 @@ const AccountRowLayout = ({ const { colors, space } = useTheme(); return ( - + {topLink && ( {name} diff --git a/apps/ledger-live-mobile/src/components/Animation.tsx b/apps/ledger-live-mobile/src/components/Animation.tsx index 30016e081fdb..c226e39dd850 100644 --- a/apps/ledger-live-mobile/src/components/Animation.tsx +++ b/apps/ledger-live-mobile/src/components/Animation.tsx @@ -45,7 +45,7 @@ export default function Animation({ {...lottieProps} style={[styles.default, { aspectRatio }, style]} loop={lottieProps.loop ?? true} - autoPlay={Config.MOCK ? false : lottieProps.autoPlay ?? true} + autoPlay={Config.DETOX ? false : lottieProps.autoPlay ?? true} /> ); diff --git a/apps/ledger-live-mobile/src/components/BleDevicePairingFlow/BleDevicePairing.tsx b/apps/ledger-live-mobile/src/components/BleDevicePairingFlow/BleDevicePairing.tsx index 5c8c3f2cf99c..3955f5859aa1 100644 --- a/apps/ledger-live-mobile/src/components/BleDevicePairingFlow/BleDevicePairing.tsx +++ b/apps/ledger-live-mobile/src/components/BleDevicePairingFlow/BleDevicePairing.tsx @@ -169,7 +169,7 @@ const BleDevicePairing = ({ deviceToPair, onPaired, onRetry }: BleDevicePairingP } + Icon={} backgroundColor={colors.opacityDefault.c05} size={64} variant="circle" diff --git a/apps/ledger-live-mobile/src/components/DeviceAction/rendering.tsx b/apps/ledger-live-mobile/src/components/DeviceAction/rendering.tsx index 29d99f1f8904..3acc3942d885 100644 --- a/apps/ledger-live-mobile/src/components/DeviceAction/rendering.tsx +++ b/apps/ledger-live-mobile/src/components/DeviceAction/rendering.tsx @@ -883,7 +883,7 @@ export function renderLoading({ return ( - + {description ?? t("DeviceAction.loading")} diff --git a/apps/ledger-live-mobile/src/components/KeyboardView.tsx b/apps/ledger-live-mobile/src/components/KeyboardView.tsx index 9e6960a8bc5f..8c407273b0a5 100644 --- a/apps/ledger-live-mobile/src/components/KeyboardView.tsx +++ b/apps/ledger-live-mobile/src/components/KeyboardView.tsx @@ -21,7 +21,7 @@ const KeyboardView = React.memo( const isExperimental = useExperimental(); const headerHeight = React.useContext(HeaderHeightContext) || 0; let behaviorParam: KeyboardAvoidingViewProps["behavior"] | undefined; - const keyboardVerticalOffset = isExperimental || Config.MOCK ? ExperimentalHeaderHeight : 0; + const keyboardVerticalOffset = isExperimental || Config.DETOX ? ExperimentalHeaderHeight : 0; if (Platform.OS === "ios") { behaviorParam = behavior || "height"; diff --git a/apps/ledger-live-mobile/src/components/LoadingFooter.tsx b/apps/ledger-live-mobile/src/components/LoadingFooter.tsx index 3099265b22d4..0798bd5a782c 100644 --- a/apps/ledger-live-mobile/src/components/LoadingFooter.tsx +++ b/apps/ledger-live-mobile/src/components/LoadingFooter.tsx @@ -11,7 +11,7 @@ export default () => { margin: 40, }} color={colors.live} - animating={!Config.MOCK} + animating={!Config.DETOX} /> ); }; diff --git a/apps/ledger-live-mobile/src/components/Nft/NftGallery/NftList.tsx b/apps/ledger-live-mobile/src/components/Nft/NftGallery/NftList.tsx index 619a02e4f1c8..9ac51b523b72 100644 --- a/apps/ledger-live-mobile/src/components/Nft/NftGallery/NftList.tsx +++ b/apps/ledger-live-mobile/src/components/Nft/NftGallery/NftList.tsx @@ -81,8 +81,8 @@ const NftList = ({ data, fetchNextPage, isLoading }: Props) => { ], }; - const Fade_In_Down = Config.MOCK ? undefined : FadeInDown; - const Fade_Out_Down = Config.MOCK ? undefined : FadeOutDown; + const Fade_In_Down = Config.DETOX ? undefined : FadeInDown; + const Fade_Out_Down = Config.DETOX ? undefined : FadeOutDown; const renderItem = useCallback( ({ item, index }: { item: ProtoNFT; index: number; count?: number }) => ( diff --git a/apps/ledger-live-mobile/src/components/RequiresBLE/hooks/useEnableBluetooth.ts b/apps/ledger-live-mobile/src/components/RequiresBLE/hooks/useEnableBluetooth.ts index c54f0972629e..ecaa2ca62e05 100644 --- a/apps/ledger-live-mobile/src/components/RequiresBLE/hooks/useEnableBluetooth.ts +++ b/apps/ledger-live-mobile/src/components/RequiresBLE/hooks/useEnableBluetooth.ts @@ -98,7 +98,7 @@ export function useEnableBluetooth( const checkAndRequestAgain = useCallback(async () => { // Early return when mocking, because when running LLM in an iOS simulator // prompting the user to enable bluetooth services will randomly crash the app - if (!isHookEnabled || Config.MOCK) return; + if (!isHookEnabled || Config.MOCK || Config.DETOX) return; // We actually can't do anything with the result, as on iOS it will always be BLE_UNKNOWN_STATE await promptBluetoothCallback(); diff --git a/apps/ledger-live-mobile/src/components/RootDrawer/InitialDrawers/PTXServicesAppleWarning.tsx b/apps/ledger-live-mobile/src/components/RootDrawer/InitialDrawers/PTXServicesAppleWarning.tsx index 4b6012c7762a..f55e9d28b42d 100644 --- a/apps/ledger-live-mobile/src/components/RootDrawer/InitialDrawers/PTXServicesAppleWarning.tsx +++ b/apps/ledger-live-mobile/src/components/RootDrawer/InitialDrawers/PTXServicesAppleWarning.tsx @@ -44,7 +44,7 @@ export function PTXServicesAppleWarning() { ); useEffect(() => { - if (!exchangeDrawerEnabled && !ctaScreensEnabled && !Config.MOCK) { + if (!exchangeDrawerEnabled && !ctaScreensEnabled && !Config.DETOX) { openDrawer(); } else { _onClose(); diff --git a/apps/ledger-live-mobile/src/components/SelectableAccountsList.tsx b/apps/ledger-live-mobile/src/components/SelectableAccountsList.tsx index 79d5aab3ecd7..b4a0bfaf616f 100644 --- a/apps/ledger-live-mobile/src/components/SelectableAccountsList.tsx +++ b/apps/ledger-live-mobile/src/components/SelectableAccountsList.tsx @@ -335,7 +335,11 @@ const Header = ({ text, areAllSelected, onSelectAll, onUnselectAll }: HeaderProp onPress={areAllSelected ? onUnselectAll : onSelectAll} hitSlop={selectAllHitSlop} > - + {areAllSelected ? ( ) : ( diff --git a/apps/ledger-live-mobile/src/components/Skeleton.tsx b/apps/ledger-live-mobile/src/components/Skeleton.tsx index 4bd12fd2d473..1a2ac52b4f40 100644 --- a/apps/ledger-live-mobile/src/components/Skeleton.tsx +++ b/apps/ledger-live-mobile/src/components/Skeleton.tsx @@ -27,7 +27,7 @@ const Skeleton: React.FC = ({ useEffect(() => { // Disable animation when mock env because it was blocking Detox tests - if (animated && !Config.MOCK) { + if (animated && !Config.DETOX) { const duration = 1000; const values = { min: 0.5, max: 1 }; diff --git a/apps/ledger-live-mobile/src/components/TabBar/Transfer.tsx b/apps/ledger-live-mobile/src/components/TabBar/Transfer.tsx index be35d5e07376..b381dd9a8080 100644 --- a/apps/ledger-live-mobile/src/components/TabBar/Transfer.tsx +++ b/apps/ledger-live-mobile/src/components/TabBar/Transfer.tsx @@ -77,7 +77,7 @@ const BackdropPressable = Animated.createAnimatedComponent(styled(Pressable)` background-color: rgba(0, 0, 0, 0.7); `); -const DURATION_MS = Config.MOCK ? 50 : 400; +const DURATION_MS = Config.DETOX ? 50 : 400; const Y_AMPLITUDE = 90; const animParams = { duration: DURATION_MS }; @@ -199,7 +199,7 @@ export function TransferTabIcon() { screenHeight - bottomInset - topInset - - (isExperimental || Config.MOCK ? ExperimentalHeaderHeight : 0); + (isExperimental || Config.DETOX ? ExperimentalHeaderHeight : 0); return ( <> @@ -213,8 +213,8 @@ export function TransferTabIcon() { maxHeight: drawerHeight, paddingBottom: bottomInset + 16 + MAIN_BUTTON_SIZE + MAIN_BUTTON_BOTTOM, }, - Config.MOCK ? {} : opacityStyle, - Config.MOCK ? {} : translateYStyle, + Config.DETOX ? {} : opacityStyle, + Config.DETOX ? {} : translateYStyle, ]} > diff --git a/apps/ledger-live-mobile/src/families/cosmos/DelegationFlow/02-Summary.tsx b/apps/ledger-live-mobile/src/families/cosmos/DelegationFlow/02-Summary.tsx index 2dcd50572893..b279b5da71ce 100644 --- a/apps/ledger-live-mobile/src/families/cosmos/DelegationFlow/02-Summary.tsx +++ b/apps/ledger-live-mobile/src/families/cosmos/DelegationFlow/02-Summary.tsx @@ -106,7 +106,7 @@ export default function DelegationSummary({ navigation, route }: Props) { const [rotateAnim] = useState(() => new Animated.Value(0)); useEffect(() => { - if (!Config.MOCK) { + if (!Config.DETOX) { Animated.loop( Animated.sequence([ Animated.timing(rotateAnim, { diff --git a/apps/ledger-live-mobile/src/index.tsx b/apps/ledger-live-mobile/src/index.tsx index 2cfc962a7b25..c0ce26ac9395 100644 --- a/apps/ledger-live-mobile/src/index.tsx +++ b/apps/ledger-live-mobile/src/index.tsx @@ -314,7 +314,7 @@ export default class Root extends Component { } onInitFinished = () => { - if (Config.MOCK) { + if (Config.DETOX) { init(); } }; diff --git a/apps/ledger-live-mobile/src/screens/Account/AccountHeaderRight.tsx b/apps/ledger-live-mobile/src/screens/Account/AccountHeaderRight.tsx index 7583dc446c95..dffadbe646f2 100644 --- a/apps/ledger-live-mobile/src/screens/Account/AccountHeaderRight.tsx +++ b/apps/ledger-live-mobile/src/screens/Account/AccountHeaderRight.tsx @@ -73,6 +73,7 @@ export default function AccountHeaderRight() { )} + , @@ -195,6 +200,7 @@ const AccountScreenInner = ({ keyExtractor={(_: unknown, index: number) => String(index)} showsVerticalScrollIndicator={false} onScroll={handleScroll} + testID={"account-screen-scrollView"} /> { return ( } arrowRight onPress={() => diff --git a/apps/ledger-live-mobile/src/screens/AccountSettings/AdvancedLogs.tsx b/apps/ledger-live-mobile/src/screens/AccountSettings/AdvancedLogs.tsx index 57b7775d6527..f576b67831a1 100644 --- a/apps/ledger-live-mobile/src/screens/AccountSettings/AdvancedLogs.tsx +++ b/apps/ledger-live-mobile/src/screens/AccountSettings/AdvancedLogs.tsx @@ -26,7 +26,7 @@ export default function AdvancedLogs({ route }: NavigationProps) { const { t } = useTranslation(); const usefulData = { xpub: (isAccount(account) && account?.xpub) || undefined, - index: (isAccount(account) && account?.index) || undefined, + index: isAccount(account) && "index" in account ? account.index : undefined, freshAddressPath: (isAccount(account) && account?.freshAddressPath) || undefined, id: account?.id || undefined, blockHeight: (isAccount(account) && account?.blockHeight) || undefined, @@ -69,7 +69,7 @@ export default function AdvancedLogs({ route }: NavigationProps) { time: readableDate, })} - + {JSON.stringify(usefulData, null, 2)} diff --git a/apps/ledger-live-mobile/src/screens/Accounts/AccountRow.tsx b/apps/ledger-live-mobile/src/screens/Accounts/AccountRow.tsx index 1b7a7398f310..16fd862b8a8b 100644 --- a/apps/ledger-live-mobile/src/screens/Accounts/AccountRow.tsx +++ b/apps/ledger-live-mobile/src/screens/Accounts/AccountRow.tsx @@ -110,6 +110,7 @@ const AccountRow = ({ currencyUnit={unit} balance={account.balance} name={name} + id={accountId} countervalueChange={countervalueChange} tag={tag} topLink={topLink} diff --git a/apps/ledger-live-mobile/src/screens/Accounts/ReadOnly/ReadOnlyAccountRow.tsx b/apps/ledger-live-mobile/src/screens/Accounts/ReadOnly/ReadOnlyAccountRow.tsx index 8d4094dbb378..00599683bcc1 100644 --- a/apps/ledger-live-mobile/src/screens/Accounts/ReadOnly/ReadOnlyAccountRow.tsx +++ b/apps/ledger-live-mobile/src/screens/Accounts/ReadOnly/ReadOnlyAccountRow.tsx @@ -31,6 +31,7 @@ const ReadOnlyAccountRow = ({ navigation, currency, screen }: Props) => { currencyUnit={units[0]} balance={new BigNumber(0)} name={name} + id={id} progress={0} /> ); diff --git a/apps/ledger-live-mobile/src/screens/AddAccounts/03-Accounts.tsx b/apps/ledger-live-mobile/src/screens/AddAccounts/03-Accounts.tsx index 7bc4695a5a7a..570aece13b10 100644 --- a/apps/ledger-live-mobile/src/screens/AddAccounts/03-Accounts.tsx +++ b/apps/ledger-live-mobile/src/screens/AddAccounts/03-Accounts.tsx @@ -350,7 +350,7 @@ function AddAccountsAccounts({ item.id} ListHeaderComponent={ScanningHeader} - ListEmptyComponent={} + ListEmptyComponent={} /> diff --git a/apps/ledger-live-mobile/src/screens/ReceiveFunds/ReceiveSecurityModal/index.tsx b/apps/ledger-live-mobile/src/screens/ReceiveFunds/ReceiveSecurityModal/index.tsx index 5df10b5c5ba9..4aa398b06245 100644 --- a/apps/ledger-live-mobile/src/screens/ReceiveFunds/ReceiveSecurityModal/index.tsx +++ b/apps/ledger-live-mobile/src/screens/ReceiveFunds/ReceiveSecurityModal/index.tsx @@ -91,7 +91,7 @@ const ReceiveSecurityModal = ({ noCloseButton preventBackdropClick > - + {component} diff --git a/apps/ledger-live-mobile/src/sentry.ts b/apps/ledger-live-mobile/src/sentry.ts index 2e8d5474bc46..331aa83079ad 100644 --- a/apps/ledger-live-mobile/src/sentry.ts +++ b/apps/ledger-live-mobile/src/sentry.ts @@ -82,7 +82,8 @@ const excludedErrorDescription = [ "Bad status on response: 503", // cryptoorg node ]; -const sentryEnabled = Config.SENTRY_DSN && (!__DEV__ || Config.FORCE_SENTRY) && !Config.MOCK; +const sentryEnabled = + Config.SENTRY_DSN && (!__DEV__ || Config.FORCE_SENTRY) && !(Config.MOCK || Config.DETOX); export function withSentry(App: React.ComponentType) { if (sentryEnabled) { diff --git a/apps/ledger-live-mobile/src/utils/constants.ts b/apps/ledger-live-mobile/src/utils/constants.ts index 21855c86e586..77740f77e277 100644 --- a/apps/ledger-live-mobile/src/utils/constants.ts +++ b/apps/ledger-live-mobile/src/utils/constants.ts @@ -1,7 +1,7 @@ import Config from "react-native-config"; export const SYNC_DELAY = 2500; -export const BLE_SCANNING_NOTHING_TIMEOUT = (Config.MOCK ? 60 : 30) * 1000; +export const BLE_SCANNING_NOTHING_TIMEOUT = (Config.DETOX ? 60 : 30) * 1000; export const GENUINE_CHECK_TIMEOUT = 120 * 1000; export const VIBRATION_PATTERN_ERROR = [0, 150]; export const LEDGER_APPLE_WARNING_EXPLAINER_LINK = diff --git a/libs/env/src/env.ts b/libs/env/src/env.ts index b4936e40f388..7e2373d2b917 100644 --- a/libs/env/src/env.ts +++ b/libs/env/src/env.ts @@ -327,6 +327,11 @@ const envDefinitions = { parser: boolParser, desc: "disable the version check for firmware update eligibility", }, + DETOX: { + def: "", + parser: stringParser, + desc: "switch the app into a DETOX mode for test purpose. Avoid falsy values.", + }, EIP1559_MINIMUM_FEES_GATE: { def: true, parser: boolParser, diff --git a/libs/ledger-live-common/.unimportedrc.json b/libs/ledger-live-common/.unimportedrc.json index 58226330923f..3d7d50acefc8 100644 --- a/libs/ledger-live-common/.unimportedrc.json +++ b/libs/ledger-live-common/.unimportedrc.json @@ -306,6 +306,13 @@ "src/deviceSDK/commands/genuineCheck.ts", "src/deviceSDK/commands/getAppAndVersion.ts", "src/deviceSDK/tasks/genuineCheck.ts", + "src/e2e/enum/Account.ts", + "src/e2e/enum/AccountType.ts", + "src/e2e/enum/AppInfos.ts", + "src/e2e/enum/Currency.ts", + "src/e2e/enum/DeviceLabels.ts", + "src/e2e/enum/Fee.ts", + "src/e2e/enum/Swap.ts", "src/exchange/swap/const/blockchain.ts", "src/families/cardano/logic.ts", "src/families/cardano/staking.ts", diff --git a/apps/ledger-live-desktop/tests/enum/Account.ts b/libs/ledger-live-common/src/e2e/enum/Account.ts similarity index 99% rename from apps/ledger-live-desktop/tests/enum/Account.ts rename to libs/ledger-live-common/src/e2e/enum/Account.ts index 7009d6eb1ae5..44c1cace564e 100644 --- a/apps/ledger-live-desktop/tests/enum/Account.ts +++ b/libs/ledger-live-common/src/e2e/enum/Account.ts @@ -1,5 +1,5 @@ import { Currency } from "./Currency"; -import { AccountType } from "tests/enum/AccountType"; +import { AccountType } from "./AccountType"; export class Account { constructor( diff --git a/apps/ledger-live-desktop/tests/enum/AccountType.ts b/libs/ledger-live-common/src/e2e/enum/AccountType.ts similarity index 100% rename from apps/ledger-live-desktop/tests/enum/AccountType.ts rename to libs/ledger-live-common/src/e2e/enum/AccountType.ts diff --git a/apps/ledger-live-desktop/tests/enum/AppInfos.ts b/libs/ledger-live-common/src/e2e/enum/AppInfos.ts similarity index 100% rename from apps/ledger-live-desktop/tests/enum/AppInfos.ts rename to libs/ledger-live-common/src/e2e/enum/AppInfos.ts diff --git a/apps/ledger-live-desktop/tests/enum/Currency.ts b/libs/ledger-live-common/src/e2e/enum/Currency.ts similarity index 98% rename from apps/ledger-live-desktop/tests/enum/Currency.ts rename to libs/ledger-live-common/src/e2e/enum/Currency.ts index c4d7c3b57a46..33b217d0657b 100644 --- a/apps/ledger-live-desktop/tests/enum/Currency.ts +++ b/libs/ledger-live-common/src/e2e/enum/Currency.ts @@ -53,7 +53,7 @@ export class Currency { "bsc", AppInfos.BINANCE_SMART_CHAIN, ); - static readonly TON = new Currency("Ton", "TON", "ton", AppInfos.TON); + static readonly TON = new Currency("TON", "TON", "ton", AppInfos.TON); static readonly ETH_USDT = new Currency("Tether USD", "USDT", "ethereum", AppInfos.ETHEREUM); static readonly ETH_LIDO = new Currency( "LIDO Staked ETH", diff --git a/apps/ledger-live-desktop/tests/enum/DeviceLabels.ts b/libs/ledger-live-common/src/e2e/enum/DeviceLabels.ts similarity index 100% rename from apps/ledger-live-desktop/tests/enum/DeviceLabels.ts rename to libs/ledger-live-common/src/e2e/enum/DeviceLabels.ts diff --git a/apps/ledger-live-desktop/tests/enum/Fee.ts b/libs/ledger-live-common/src/e2e/enum/Fee.ts similarity index 100% rename from apps/ledger-live-desktop/tests/enum/Fee.ts rename to libs/ledger-live-common/src/e2e/enum/Fee.ts diff --git a/apps/ledger-live-desktop/tests/enum/Swap.ts b/libs/ledger-live-common/src/e2e/enum/Swap.ts similarity index 100% rename from apps/ledger-live-desktop/tests/enum/Swap.ts rename to libs/ledger-live-common/src/e2e/enum/Swap.ts diff --git a/libs/ledger-live-common/src/hw/actions/implementations.ts b/libs/ledger-live-common/src/hw/actions/implementations.ts index f2cca5571899..63470b675db5 100644 --- a/libs/ledger-live-common/src/hw/actions/implementations.ts +++ b/libs/ledger-live-common/src/hw/actions/implementations.ts @@ -63,7 +63,7 @@ export const defaultImplementationConfig: PollingImplementationConfig = { pollingFrequency: 2000, initialWaitTime: 5000, reconnectWaitTime: 5000, - connectionTimeout: getEnv("MOCK") ? 60000 : 20000, + connectionTimeout: getEnv("DETOX") ? 60000 : 20000, }; type Implementation = ( params: PollingImplementationParams, diff --git a/libs/ledger-live-common/src/platform/providers/RemoteLiveAppProvider/api/index.ts b/libs/ledger-live-common/src/platform/providers/RemoteLiveAppProvider/api/index.ts index ee5db24befe3..aee10c2172d1 100644 --- a/libs/ledger-live-common/src/platform/providers/RemoteLiveAppProvider/api/index.ts +++ b/libs/ledger-live-common/src/platform/providers/RemoteLiveAppProvider/api/index.ts @@ -7,7 +7,7 @@ import mockData from "./mock.json"; const api = { fetchLiveAppManifests: async (url: string, params?: FilterParams): Promise => { - if (getEnv("MOCK")) { + if (getEnv("MOCK") || getEnv("DETOX")) { if (getEnv("MOCK_REMOTE_LIVE_MANIFEST")) { return [ ...mockData, diff --git a/libs/speculos-transport/src/index.ts b/libs/speculos-transport/src/index.ts index d365acb56b46..16b33ff782b7 100644 --- a/libs/speculos-transport/src/index.ts +++ b/libs/speculos-transport/src/index.ts @@ -24,13 +24,13 @@ export type SpeculosDeviceInternal = buttonPort: number; automationPort: number; transport: SpeculosTransportWebsocket; - destroy: () => void; + destroy: () => Promise; } | { process: ChildProcessWithoutNullStreams; apiPort: string | undefined; transport: SpeculosTransportHttp; - destroy: () => void; + destroy: () => Promise; }; // FIXME we need to figure out a better system, using a filesystem file? @@ -235,10 +235,10 @@ export async function createSpeculosDevice( }); let destroyed = false; - const destroy = () => { + const destroy = async () => { if (destroyed) return; destroyed = true; - new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { if (!data[speculosID]) return; delete data[speculosID]; exec(`docker rm -f ${speculosID}`, (error, stdout, stderr) => { @@ -259,7 +259,7 @@ export async function createSpeculosDevice( } }); let latestStderr: string | undefined; - p.stderr.on("data", data => { + p.stderr.on("data", async data => { if (!data) return; latestStderr = data; @@ -276,16 +276,16 @@ export async function createSpeculosDevice( } else if (data.includes("address already in use")) { if (maxRetry > 0) { log("speculos", "retrying speculos connection"); - destroy(); + await destroy(); resolveReady(false); } } }); - p.on("close", () => { + p.on("close", async () => { log("speculos", `${speculosID} closed`); if (!destroyed) { - destroy(); + await destroy(); rejectReady(new Error(`speculos process failure. ${latestStderr || ""}`)); } });