From 2e7700fc315dcb3b6f40745d137ee8ef392e9a99 Mon Sep 17 00:00:00 2001 From: Ondrej Hajek Date: Fri, 3 Oct 2025 12:44:37 +0200 Subject: [PATCH 1/2] feat(e2e): Test ID for THP pairing code inputs --- suite-native/thp/src/components/SecurityCodeInput.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/suite-native/thp/src/components/SecurityCodeInput.tsx b/suite-native/thp/src/components/SecurityCodeInput.tsx index d8a1c7793375..d1ba202bc28a 100644 --- a/suite-native/thp/src/components/SecurityCodeInput.tsx +++ b/suite-native/thp/src/components/SecurityCodeInput.tsx @@ -7,6 +7,7 @@ import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; type DigitBoxProps = { value?: string; isFocused: boolean; + testID?: string; }; const digitBoxStyle = prepareNativeStyle<{ isFocused: boolean }>( @@ -104,6 +105,7 @@ export const SecurityCodeInput = ({ length, onSubmit }: SecurityCodeInputProps) key={i} value={code.at(i)} isFocused={isFocused && i === code.length} + testID={`@thpSecurityCode/Input/${i}`} /> ))} From 9a9e1af8a8be08d9873edee99267c61236d3f83a Mon Sep 17 00:00:00 2001 From: Ondrej Hajek Date: Tue, 14 Oct 2025 15:57:16 +0200 Subject: [PATCH 2/2] feat(ci): Added T3W1 to Suite Native android E2E test job --- .../test-suite-native-e2e-android-t3w1.yml | 48 -- .../test-suite-native-e2e-android.yml | 12 + ...te.ts => btcDiscoveryFinishedStateT3T1.ts} | 2 +- .../fixtures/btcDiscoveryFinishedStateT3W1.ts | 228 +++++++++ .../e2e/fixtures/deviceChecksDisabledState.ts | 12 + .../regtestDiscoveryFinishedStateT3W1.ts | 454 ++++++++++++++++++ .../pageObjects/deviceOnboardingActions.ts | 12 + .../e2e/pageObjects/devicePromptActions.ts | 13 + .../app/e2e/pageObjects/passphraseModule.ts | 9 +- .../app/e2e/tests/coinEnabling.test.ts | 9 +- .../app/e2e/tests/deeplinkPopup.test.ts | 19 +- .../app/e2e/tests/deviceOnboarding.test.ts | 16 +- .../app/e2e/tests/ejectWallets.test.ts | 14 +- .../app/e2e/tests/onboardAndConnect.test.ts | 22 +- .../app/e2e/tests/passphraseFlow.test.ts | 13 +- suite-native/app/e2e/tests/receive.test.ts | 15 +- suite-native/app/e2e/tests/send.test.ts | 21 +- suite-native/app/e2e/utils.ts | 17 +- .../thp/src/components/SecurityCodeInput.tsx | 13 +- 19 files changed, 876 insertions(+), 73 deletions(-) delete mode 100644 .github/workflows/test-suite-native-e2e-android-t3w1.yml rename suite-native/app/e2e/fixtures/{btcDiscoveryFinishedState.ts => btcDiscoveryFinishedStateT3T1.ts} (99%) create mode 100644 suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3W1.ts create mode 100644 suite-native/app/e2e/fixtures/deviceChecksDisabledState.ts create mode 100644 suite-native/app/e2e/fixtures/regtestDiscoveryFinishedStateT3W1.ts create mode 100644 suite-native/app/e2e/pageObjects/devicePromptActions.ts diff --git a/.github/workflows/test-suite-native-e2e-android-t3w1.yml b/.github/workflows/test-suite-native-e2e-android-t3w1.yml deleted file mode 100644 index 5033165da128..000000000000 --- a/.github/workflows/test-suite-native-e2e-android-t3w1.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: "[Test] suite-native Android E2E (T3W1)" - -permissions: - id-token: write # for fetching the OIDC token (needed for aws s3 actions) - -on: - # schedule: - # - cron: "0 0 * * *" - # pull_request: - # paths: - # - "suite-native/**" - # - "suite-common/**" - # - "packages/connect/**" - # - ".github/workflows/test-suite-native-e2e-android-t3w1.yml" - # - ".github/workflows/template-suite-native-e2e-android.yml" - # - ".github/workflows/template-suite-native-prepare-test-app-android.yml" - # - "!**.md" - # push: - # branches: - # - release-native/* - workflow_dispatch: - inputs: - publish_results_to_github: - description: "Publish test report to GitHub Project" - required: false - default: false - type: boolean - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - prepare_android_test_app: - uses: ./.github/workflows/template-suite-native-prepare-test-app-android.yml - secrets: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - run_android_e2e_tests: - uses: ./.github/workflows/template-suite-native-e2e-android.yml - needs: prepare_android_test_app - with: - emulator_model: "T3W1" - jest_test_name_pattern: "^(?!.*@specificModel)" # exclude @specificModel tests - publish_results_to_github: ${{ inputs.publish_results_to_github == true }} - secrets: - TREZOR_BOT_APP_ID: ${{ secrets.TREZOR_BOT_APP_ID }} - TREZOR_BOT_PRIVATE_KEY: ${{ secrets.TREZOR_BOT_PRIVATE_KEY }} - CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} diff --git a/.github/workflows/test-suite-native-e2e-android.yml b/.github/workflows/test-suite-native-e2e-android.yml index c0c65a92e1e1..d3027cb254ca 100644 --- a/.github/workflows/test-suite-native-e2e-android.yml +++ b/.github/workflows/test-suite-native-e2e-android.yml @@ -46,3 +46,15 @@ jobs: TREZOR_BOT_PRIVATE_KEY: ${{ secrets.TREZOR_BOT_PRIVATE_KEY }} CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} SLACK_MOBILE_E2E_WEBHOOK: ${{ secrets.SLACK_MOBILE_E2E_WEBHOOK }} + run_android_e2e_tests_t3w1: + uses: ./.github/workflows/template-suite-native-e2e-android.yml + needs: prepare_android_test_app + with: + emulator_model: "T3W1" + jest_test_name_pattern: "^(?!.*@specificModel)" # exclude @specificModel tests + publish_results_to_github: ${{ inputs.publish_results_to_github == true }} + secrets: + TREZOR_BOT_APP_ID: ${{ secrets.TREZOR_BOT_APP_ID }} + TREZOR_BOT_PRIVATE_KEY: ${{ secrets.TREZOR_BOT_PRIVATE_KEY }} + CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} + SLACK_MOBILE_E2E_WEBHOOK: ${{ secrets.SLACK_MOBILE_E2E_WEBHOOK }} \ No newline at end of file diff --git a/suite-native/app/e2e/fixtures/btcDiscoveryFinishedState.ts b/suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3T1.ts similarity index 99% rename from suite-native/app/e2e/fixtures/btcDiscoveryFinishedState.ts rename to suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3T1.ts index 3cdfec77ea2c..4383c187121b 100644 --- a/suite-native/app/e2e/fixtures/btcDiscoveryFinishedState.ts +++ b/suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3T1.ts @@ -4,7 +4,7 @@ import { PreloadedState } from '@suite-native/state'; /** * reflects state after BTC discovery of connected device with `mnemonic_immune` seed from @packages/trezor-user-env-link constants. */ -export const btcDiscoveryFinishedState: PreloadedState = { +export const btcDiscoveryFinishedStateT3T1: PreloadedState = { wallet: { accounts: [ { diff --git a/suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3W1.ts b/suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3W1.ts new file mode 100644 index 000000000000..b949785f7215 --- /dev/null +++ b/suite-native/app/e2e/fixtures/btcDiscoveryFinishedStateT3W1.ts @@ -0,0 +1,228 @@ +import { TrezorDevice } from '@suite-common/suite-types'; +import { PreloadedState } from '@suite-native/state'; + +/** + * reflects state after BTC discovery of connected device with `mnemonic_immune` seed from @packages/trezor-user-env-link constants. + */ +export const btcDiscoveryFinishedStateT3W1: PreloadedState = { + appSettings: { + isCoinEnablingInitFinished: true, + }, + wallet: { + accounts: [ + { + deviceState: 'mt5WPmXL77AJwhCPPv6Gct3UtiuVUMieXJ@7ED4F891C5F1098B60B881DE:1', + symbol: 'btc', + index: 0, + accountType: 'segwit', + path: 'm/49\'/0\'/0\'', + backendType: 'blockbook', + visible: true, + descriptor: 'ypub6X4Sd4gegPV8ZwEhuq8rUCHwWb2Re8u7TtEaRNugmWSxor2w2PAQnx7qyqHqLDw7s9JWK7u6TvP5nYFF92jmM7Z6U42bYhHTNhQijYTLHAL', + empty: true, + balance: '0', + availableBalance: '0', + history: { + total: 0, + unconfirmed: 0 + }, + key: 'ypub6X4Sd4gegPV8ZwEhuq8rUCHwWb2Re8u7TtEaRNugmWSxor2w2PAQnx7qyqHqLDw7s9JWK7u6TvP5nYFF92jmM7Z6U42bYhHTNhQijYTLHAL-btc-mt5WPmXL77AJwhCPPv6Gct3UtiuVUMieXJ@7ED4F891C5F1098B60B881DE:1', + formattedBalance: '0', + tokens: [], + addresses: { + change: [], + used: [], + unused: [] + }, + utxo: [], + metadata: { + key: 'xpub6CEBKQ1jXhweie3b5UMEG7CSLcsyhWucYmiMdz1oPW55kkDhmizrAtThxdLFLKHCTWBhZeJY1G2XuFdgRLKkYssVbiLAxnTy6yM5Lzt5YMc' + }, + ts: 1760446304591, + networkType: 'bitcoin', + page: { + index: 1, + size: 25, + total: 1 + }, + accountLabel: 'Bitcoin #1' + }, + ], + settings: { + enabledNetworks: ['btc'], + }, + }, + device: { + devices: [ + { + path: 'e2c6cc1b', + name: 'Trezor Safe 7', + descriptor: { + apiType: 'usb', + id: '127.0.0.1:21324' + }, + type: 'acquired', + id: '7ED4F891C5F1098B60B881DE', + label: 'Hello!', + state: { + sessionId: '01', + deriveCardano: false, + staticSessionId: 'mt5WPmXL77AJwhCPPv6Gct3UtiuVUMieXJ@7ED4F891C5F1098B60B881DE:1' + }, + status: 'available', + mode: 'normal', + firmware: 'custom', + firmwareType: 'universal', + features: { + vendor: 'trezor.io', + major_version: 2, + minor_version: 9, + patch_version: 3, + bootloader_mode: null, + device_id: '7ED4F891C5F1098B60B881DE', + pin_protection: false, + passphrase_protection: true, + language: 'en-US', + label: 'Hello!', + initialized: true, + revision: 'f24354b914d6b5cacb43dbb1c00ea6dbfc13ea37', + bootloader_hash: null, + imported: null, + unlocked: true, + _passphrase_cached: null, + firmware_present: null, + backup_availability: 'NotAvailable', + flags: 0, + model: 'Safe 7', + fw_major: null, + fw_minor: null, + fw_patch: null, + fw_vendor: 'EMULATOR', + unfinished_backup: false, + no_backup: false, + recovery_status: 'Nothing', + capabilities: [ + 'Capability_Bitcoin', + 'Capability_Bitcoin_like', + 'Capability_Binance', + 'Capability_Cardano', + 'Capability_Crypto', + 'Capability_Ethereum', + 'Capability_Monero', + 'Capability_Ripple', + 'Capability_Stellar', + 'Capability_Tezos', + 'Capability_U2F', + 'Capability_Shamir', + 'Capability_ShamirGroups', + 'Capability_PassphraseEntry', + 'Capability_Solana', + 'Capability_Translations', + 'Capability_Brightness', + 'Capability_BLE', + 'Capability_NFC' + ], + backup_type: 'Bip39', + sd_card_present: false, + sd_protection: false, + wipe_code_protection: false, + session_id: null, + passphrase_always_on_device: false, + safety_checks: 'Strict', + auto_lock_delay_ms: 600000, + display_rotation: 'North', + experimental_features: false, + busy: false, + homescreen_format: 'Jpeg', + hide_passphrase_from_host: false, + internal_model: 'T3W1', + unit_color: null, + unit_btconly: null, + homescreen_width: 380, + homescreen_height: 520, + bootloader_locked: true, + language_version_matches: true, + unit_packaging: null, + haptic_feedback: null, + optiga_sec: 0, + soc: 100, + firmware_corrupted: null + }, + unavailableCapabilities: { + btg: 'no-support', + tbtg: 'no-support', + dash: 'no-support', + tdash: 'no-support', + dcr: 'no-support', + tdcr: 'no-support', + dgb: 'no-support', + nmc: 'no-support', + vtc: 'no-support', + eos: 'no-support', + xem: 'no-support', + dim: 'no-support', + dimtok: 'no-support', + breeze: 'no-support', + 'pac:hrt': 'no-support', + 'pac:chs': 'no-support', + maid: 'no-capability', + omni: 'no-capability', + usdt: 'no-capability' + }, + availableTranslations: {}, + authenticityChecks: { + firmwareRevision: { + success: false, + error: 'firmware-version-unknown' + }, + firmwareHash: { + success: false, + error: 'check-skipped', + attemptCount: 1 + } + }, + thp: { + properties: { + internal_model: 'T3W1', + model_variant: 0, + protocol_version_major: 2, + protocol_version_minor: 0, + pairing_methods: [ + 'CodeEntry', + 'QrCode', + 'NFC', + 'SkipPairing' + ] + }, + channel: '81fa', + sendBit: 0, + recvBit: 0, + sendNonce: 2, + recvNonce: 3, + expectedResponses: [], + credentials: [ + { + trezor_static_public_key: '566f6976fd42cafadf1b843ce4e6275c930d52efac878217df0ea2a23933b07d', + credential: '0a240a1273646b5f6770686f6e6536345f61726d363410001a0c5472657a6f722053756974651220bca002b28c2c5f5495d1857b930d4a4253bf378deb3f0841c06f6da5c8c20f40', + autoconnect: false, + connectionCounter: 1 + } + ] + }, + connected: true, + buttonRequests: [], + metadata: {}, + passwords: {}, + firstConnectedTimestamp: 1760443407224, + ts: 1760446306237, + useEmptyPassphrase: true, + remember: true, + temporaryRemember: false, + available: true, + instance: 1, + walletNumber: 1, + discovered: true + } as unknown as TrezorDevice, + ], + }, +}; diff --git a/suite-native/app/e2e/fixtures/deviceChecksDisabledState.ts b/suite-native/app/e2e/fixtures/deviceChecksDisabledState.ts new file mode 100644 index 000000000000..dbdba1221b60 --- /dev/null +++ b/suite-native/app/e2e/fixtures/deviceChecksDisabledState.ts @@ -0,0 +1,12 @@ +import { PreloadedState } from '@suite-native/state'; + +/** + * State fragment that ensures that the device security checks are enabled. + */ +export const deviceChecksDisabledState: PreloadedState = { + appSettings: { + isDeviceAuthenticityCheckEnabled: false, + isFirmwareRevisionCheckEnabled: false, + isFirmwareHashCheckEnabled: false, + }, +}; diff --git a/suite-native/app/e2e/fixtures/regtestDiscoveryFinishedStateT3W1.ts b/suite-native/app/e2e/fixtures/regtestDiscoveryFinishedStateT3W1.ts new file mode 100644 index 000000000000..60718dc0404f --- /dev/null +++ b/suite-native/app/e2e/fixtures/regtestDiscoveryFinishedStateT3W1.ts @@ -0,0 +1,454 @@ +import { TrezorDevice } from '@suite-common/suite-types'; +import { PreloadedState } from '@suite-native/state'; + +/** + * reflects state after REGTEST discovery of connected T3W1 device with `mnemonic_immune` seed from @packages/trezor-user-env-link constants. + */ +export const regtestDiscoveryFinishedStateT3W1: PreloadedState = { + appSettings: { + isCoinEnablingInitFinished: true, + areTestnetsEnabled: true, + }, + wallet: { + settings: { + enabledNetworks: ['regtest'], + }, + accounts: [ + { + deviceState: 'mt5WPmXL77AJwhCPPv6Gct3UtiuVUMieXJ@7ED4F891C5F1098B60B881DE:0', + symbol: 'regtest', + index: 0, + accountType: 'normal', + path: 'm/84\'/1\'/0\'', + visible: true, + descriptor: 'vpub5YHfp9RSUHcKc7Nu9KbS7TsiBENUMJiQAMiJhCNdQA8cDzqzL4rr7VZThZPbMCXYnASdHQurixwwjPKFr8THXUUT4567PsM4gfqDi87kXxS', + empty: false, + balance: '314000000', + availableBalance: '314000000', + history: { + total: 1, + unconfirmed: 0, + addrTxCount: 1 + }, + key: 'vpub5YHfp9RSUHcKc7Nu9KbS7TsiBENUMJiQAMiJhCNdQA8cDzqzL4rr7VZThZPbMCXYnASdHQurixwwjPKFr8THXUUT4567PsM4gfqDi87kXxS-regtest-mt5WPmXL77AJwhCPPv6Gct3UtiuVUMieXJ@7ED4F891C5F1098B60B881DE:0', + formattedBalance: '3.14', + tokens: [], + addresses: { + change: [ + { + address: 'bcrt1q5tj9l6s77h8gxx89fxacaanpgcfks7vrgrez89', + path: 'm/84\'/1\'/0\'/1/0', + transfers: 0 + }, + { + address: 'bcrt1qm8v98mevmdphpveazekvacyeapxyleufcpaqvf', + path: 'm/84\'/1\'/0\'/1/1', + transfers: 0 + }, + { + address: 'bcrt1qmms0mvtaje8lf7fg4s2cv9meu5qv2kfpycygee', + path: 'm/84\'/1\'/0\'/1/2', + transfers: 0 + }, + { + address: 'bcrt1q8x6v72qcnjqydju9ws8z0gz56pw9hlxv3gwppy', + path: 'm/84\'/1\'/0\'/1/3', + transfers: 0 + }, + { + address: 'bcrt1qccxrqpppgmhvxcj7r6hkhjjrt8wj9rggwl0wpp', + path: 'm/84\'/1\'/0\'/1/4', + transfers: 0 + }, + { + address: 'bcrt1qrjzjrv4vu3k6zq6et6sghamwj02dtsujsuvmfa', + path: 'm/84\'/1\'/0\'/1/5', + transfers: 0 + }, + { + address: 'bcrt1qz66vsttwvg4r92vwz3zswtct6r5nju2dkf9hy0', + path: 'm/84\'/1\'/0\'/1/6', + transfers: 0 + }, + { + address: 'bcrt1qlragehzl4vqcrdzhucgn8ej3mkm30g9sqrjgv6', + path: 'm/84\'/1\'/0\'/1/7', + transfers: 0 + }, + { + address: 'bcrt1qfw43engyc2pduw0lrhtucju3hhwj49yra0mvz0', + path: 'm/84\'/1\'/0\'/1/8', + transfers: 0 + }, + { + address: 'bcrt1qajvxq2lgyzteaky5my7s3f9vfr35yjnhy6atq2', + path: 'm/84\'/1\'/0\'/1/9', + transfers: 0 + }, + { + address: 'bcrt1qh2wanz06agpunvtc879p9rmn480rdyvf7ymdlr', + path: 'm/84\'/1\'/0\'/1/10', + transfers: 0 + }, + { + address: 'bcrt1q5dn0emlnhcw9lcscsw5s69cfsgp4km9cwfcf2z', + path: 'm/84\'/1\'/0\'/1/11', + transfers: 0 + }, + { + address: 'bcrt1qp2xfv0sd00dw3lk9vxeu52zcchjt9tlr9c4xh0', + path: 'm/84\'/1\'/0\'/1/12', + transfers: 0 + }, + { + address: 'bcrt1qk2qrzar7jueakt9s5j9zanplgqh3k8k02fhvgv', + path: 'm/84\'/1\'/0\'/1/13', + transfers: 0 + }, + { + address: 'bcrt1q5hhtqkpwtqmg0lujkxtucl7fxh6kavmgfagzcz', + path: 'm/84\'/1\'/0\'/1/14', + transfers: 0 + }, + { + address: 'bcrt1q2w4pmayeqggg8sevenx55ehec3mdngcdh79lsq', + path: 'm/84\'/1\'/0\'/1/15', + transfers: 0 + }, + { + address: 'bcrt1qq3jxl2va2zjddj4hzz6m2u3ld7le306kgz0y2n', + path: 'm/84\'/1\'/0\'/1/16', + transfers: 0 + }, + { + address: 'bcrt1qsdkk4wm4v88m2t08mvmc2npf385uhxgzjjq2dd', + path: 'm/84\'/1\'/0\'/1/17', + transfers: 0 + }, + { + address: 'bcrt1q9x7p7cp5ylvu0v0ajlrp866pcnxa3lrhlmpxue', + path: 'm/84\'/1\'/0\'/1/18', + transfers: 0 + }, + { + address: 'bcrt1qq2upezxxuwacklj7vzgf0tf3ltzaf44hvwethv', + path: 'm/84\'/1\'/0\'/1/19', + transfers: 0 + }, + { + address: 'bcrt1qlnyjk7jstgdxkq362tggez5r0lpagchqtgp6cc', + path: 'm/84\'/1\'/0\'/1/20', + transfers: 0 + } + ], + used: [ + { + address: 'bcrt1q34up3cga3fkmph47t22mpk5d0xxj3ppghph9da', + path: 'm/84\'/1\'/0\'/0/0', + transfers: 1, + balance: '314000000', + sent: '0', + received: '314000000' + } + ], + unused: [ + { + address: 'bcrt1qxcxh4qh3a73myvtxfqdhv55n8met98rscdfva6', + path: 'm/84\'/1\'/0\'/0/1', + transfers: 0 + }, + { + address: 'bcrt1qxvnn0adw7d3a2c6d8yge9xzw6g4gv0ykwvr5n7', + path: 'm/84\'/1\'/0\'/0/2', + transfers: 0 + }, + { + address: 'bcrt1q34v6ytf0dt9nkfcrzx9zra07qyxxlj5h2txv3u', + path: 'm/84\'/1\'/0\'/0/3', + transfers: 0 + }, + { + address: 'bcrt1qsk3h598e6zjjf5urttfkxutryd7f0ysk633uz9', + path: 'm/84\'/1\'/0\'/0/4', + transfers: 0 + }, + { + address: 'bcrt1qk2hz8da2qvsyadddnlse9qmyu80yznnukwngef', + path: 'm/84\'/1\'/0\'/0/5', + transfers: 0 + }, + { + address: 'bcrt1qzz8y4d5r9v5fxrmr0pxpunqu9tyqv3uxzvf2hq', + path: 'm/84\'/1\'/0\'/0/6', + transfers: 0 + }, + { + address: 'bcrt1qg7vknpwazylfypkauw02njrz6namtkvn2znxgy', + path: 'm/84\'/1\'/0\'/0/7', + transfers: 0 + }, + { + address: 'bcrt1q8tqr38mr9cxk0wzuxz797t4afe4eajhdjjctpn', + path: 'm/84\'/1\'/0\'/0/8', + transfers: 0 + }, + { + address: 'bcrt1qgf89hhpks9gmde68zed85ls2na98yw0qllw9lx', + path: 'm/84\'/1\'/0\'/0/9', + transfers: 0 + }, + { + address: 'bcrt1q85dhfhn5kgwhy47hxm8p0d0jutqu2z7jvp25vx', + path: 'm/84\'/1\'/0\'/0/10', + transfers: 0 + }, + { + address: 'bcrt1qdd2wp7rclhyusdjvakrlz07r4t5rg2vym9t6an', + path: 'm/84\'/1\'/0\'/0/11', + transfers: 0 + }, + { + address: 'bcrt1qelv5dspn9qdmmkwhkjn8d0ucmq74xmg2vfglm3', + path: 'm/84\'/1\'/0\'/0/12', + transfers: 0 + }, + { + address: 'bcrt1qkhs3zp7cyn9t62geed0rrqnh688edy94k4ykpj', + path: 'm/84\'/1\'/0\'/0/13', + transfers: 0 + }, + { + address: 'bcrt1qwmfwss488gdwutssxzcj600auzc4msrcxd7lff', + path: 'm/84\'/1\'/0\'/0/14', + transfers: 0 + }, + { + address: 'bcrt1qaq7kfxza86r3pxul2zqqcjlxuqdx8xpsx88z5a', + path: 'm/84\'/1\'/0\'/0/15', + transfers: 0 + }, + { + address: 'bcrt1qg9w776jgx0m7yx9uvuykz2yxmhsjpetlfkg63d', + path: 'm/84\'/1\'/0\'/0/16', + transfers: 0 + }, + { + address: 'bcrt1q88y63cd2n88mggaze5v4s3ndkjyxhtpxwms4n5', + path: 'm/84\'/1\'/0\'/0/17', + transfers: 0 + }, + { + address: 'bcrt1qq5f0srmztczw04ugdj0chljah9qmlsac94ts6n', + path: 'm/84\'/1\'/0\'/0/18', + transfers: 0 + }, + { + address: 'bcrt1q2dykjx255t0r5h0apyuu40xx994a07dpurz8tg', + path: 'm/84\'/1\'/0\'/0/19', + transfers: 0 + }, + { + address: 'bcrt1qm8pj5nskyu87xpes2m2gr4usl9p7akn6l7ymua', + path: 'm/84\'/1\'/0\'/0/20', + transfers: 0 + } + ] + }, + utxo: [ + { + txid: 'd8080efaf96bef9595261a637bd45ced0f87534afa985c8a2f219d26ef0310a6', + vout: 0, + amount: '314000000', + blockHeight: 151, + address: 'bcrt1q34up3cga3fkmph47t22mpk5d0xxj3ppghph9da', + path: 'm/84\'/1\'/0\'/0/0', + confirmations: 1 + } + ], + metadata: { + key: 'tpubDCKpwiaxUvejaVwzGE9mjZQ5rHm2DwCTYDM3cYDYW5eG5V99uc34W4YZz1PYsWndPMD9PwcrBPV6C92zgP8Z1PHwrMEGFDeGp5YvFLxtP2P' + }, + ts: 1760428935967, + networkType: 'bitcoin', + page: { + index: 1, + size: 25, + total: 1 + }, + accountLabel: 'Bitcoin Regtest #1' + }, + ], + }, + device: { + devices: [ + { + path: 'e1bdc5f1', + name: 'Trezor Safe 7', + descriptor: { + apiType: 'usb', + id: '127.0.0.1:21324' + }, + type: 'acquired', + id: '7ED4F891C5F1098B60B881DE', + label: 'My Trezor', + state: { + staticSessionId: 'mt5WPmXL77AJwhCPPv6Gct3UtiuVUMieXJ@7ED4F891C5F1098B60B881DE:0', + sessionId: '01', + deriveCardano: false + }, + status: 'available', + mode: 'normal', + firmware: 'custom', + firmwareType: 'universal', + features: { + vendor: 'trezor.io', + major_version: 2, + minor_version: 9, + patch_version: 3, + bootloader_mode: null, + device_id: '7ED4F891C5F1098B60B881DE', + pin_protection: false, + passphrase_protection: false, + language: 'en-US', + label: null, + initialized: true, + revision: 'f24354b914d6b5cacb43dbb1c00ea6dbfc13ea37', + bootloader_hash: null, + imported: null, + unlocked: true, + _passphrase_cached: null, + firmware_present: null, + backup_availability: 'NotAvailable', + flags: 0, + model: 'Safe 7', + fw_major: null, + fw_minor: null, + fw_patch: null, + fw_vendor: 'EMULATOR', + unfinished_backup: false, + no_backup: false, + recovery_status: 'Nothing', + capabilities: [ + 'Capability_Bitcoin', + 'Capability_Bitcoin_like', + 'Capability_Binance', + 'Capability_Cardano', + 'Capability_Crypto', + 'Capability_Ethereum', + 'Capability_Monero', + 'Capability_Ripple', + 'Capability_Stellar', + 'Capability_Tezos', + 'Capability_U2F', + 'Capability_Shamir', + 'Capability_ShamirGroups', + 'Capability_PassphraseEntry', + 'Capability_Solana', + 'Capability_Translations', + 'Capability_Brightness', + 'Capability_BLE', + 'Capability_NFC' + ], + backup_type: 'Bip39', + sd_card_present: false, + sd_protection: false, + wipe_code_protection: false, + session_id: null, + passphrase_always_on_device: false, + safety_checks: 'Strict', + auto_lock_delay_ms: 600000, + display_rotation: 'North', + experimental_features: false, + busy: false, + homescreen_format: 'Jpeg', + hide_passphrase_from_host: false, + internal_model: 'T3W1', + unit_color: null, + unit_btconly: null, + homescreen_width: 380, + homescreen_height: 520, + bootloader_locked: true, + language_version_matches: true, + unit_packaging: null, + haptic_feedback: null, + optiga_sec: 0, + soc: 100, + firmware_corrupted: null + }, + unavailableCapabilities: { + btg: 'no-support', + tbtg: 'no-support', + dash: 'no-support', + tdash: 'no-support', + dcr: 'no-support', + tdcr: 'no-support', + dgb: 'no-support', + nmc: 'no-support', + vtc: 'no-support', + eos: 'no-support', + xem: 'no-support', + dim: 'no-support', + dimtok: 'no-support', + breeze: 'no-support', + 'pac:hrt': 'no-support', + 'pac:chs': 'no-support', + maid: 'no-capability', + omni: 'no-capability', + usdt: 'no-capability' + }, + availableTranslations: {}, + authenticityChecks: { + firmwareRevision: { + success: false, + error: 'firmware-version-unknown' + }, + firmwareHash: { + success: false, + error: 'check-skipped', + attemptCount: 1 + } + }, + thp: { + properties: { + internal_model: 'T3W1', + model_variant: 0, + protocol_version_major: 2, + protocol_version_minor: 0, + pairing_methods: [ + 'CodeEntry', + 'QrCode', + 'NFC', + 'SkipPairing' + ] + }, + channel: '8205', + sendBit: 0, + recvBit: 0, + sendNonce: 2, + recvNonce: 3, + expectedResponses: [], + credentials: [ + { + trezor_static_public_key: '566f6976fd42cafadf1b843ce4e6275c930d52efac878217df0ea2a23933b07d', + credential: '0a240a1273646b5f6770686f6e6536345f61726d363410001a0c5472657a6f7220537569746512200a2c35e21fc72f70b5cddcfba5aface516c57e31810dd442ff9ef6dfc8657eff', + autoconnect: false, + connectionCounter: 1 + } + ] + }, + connected: true, + buttonRequests: [], + metadata: {}, + passwords: {}, + firstConnectedTimestamp: 1760363102751, + ts: 1760428936891, + useEmptyPassphrase: true, + remember: true, + temporaryRemember: false, + available: true, + walletNumber: 1, + discovered: true + } as unknown as TrezorDevice, + ], + }, +}; diff --git a/suite-native/app/e2e/pageObjects/deviceOnboardingActions.ts b/suite-native/app/e2e/pageObjects/deviceOnboardingActions.ts index 31b275d5aaad..58a360f8425e 100644 --- a/suite-native/app/e2e/pageObjects/deviceOnboardingActions.ts +++ b/suite-native/app/e2e/pageObjects/deviceOnboardingActions.ts @@ -1,4 +1,5 @@ import { BackupType } from '@suite-common/suite-types'; +import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; import { scrollUntilVisible, waitForElementByIdToBeVisible } from '../utils'; @@ -122,6 +123,17 @@ class DeviceOnboardingActions { ); } } + + async enterTHPPairingCode() { + await waitForElementByIdToBeVisible('@screen/ThpCodeEntry'); + const screenContent = await TrezorUserEnvLink.getScreenContent(); + const screenContentBody = screenContent.body as string; + const code = + screenContentBody + .match(/(\d\s*){6}$/)?.[0] + .replace(/\s+/g, '') ?? ''; + await element(by.id('@thpSecurityCode/Input')).replaceText(code); + } } export const onDeviceOnboarding = new DeviceOnboardingActions(); diff --git a/suite-native/app/e2e/pageObjects/devicePromptActions.ts b/suite-native/app/e2e/pageObjects/devicePromptActions.ts new file mode 100644 index 000000000000..49cae7b4ddf2 --- /dev/null +++ b/suite-native/app/e2e/pageObjects/devicePromptActions.ts @@ -0,0 +1,13 @@ +import { TrezorUserEnvLink } from "@trezor/trezor-user-env-link"; + +import { waitForElementByIdToBeVisible } from "../utils"; + +class DevicePromptActions { + async allowConnectToTrezor() { + await waitForElementByIdToBeVisible('@screen/ThpConfirmation'); + await TrezorUserEnvLink.pressYes(); + } + +} + +export const onDevicePrompt = new DevicePromptActions(); diff --git a/suite-native/app/e2e/pageObjects/passphraseModule.ts b/suite-native/app/e2e/pageObjects/passphraseModule.ts index 74af083f92dc..21a50721658c 100644 --- a/suite-native/app/e2e/pageObjects/passphraseModule.ts +++ b/suite-native/app/e2e/pageObjects/passphraseModule.ts @@ -2,7 +2,7 @@ import { expect as detoxExpect } from 'detox'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; -import { waitForElementByIdToBeVisible, waitForElementByTextToBeVisible } from '../utils'; +import { getModelFromEnv, waitForElementByIdToBeVisible, waitForElementByTextToBeVisible } from '../utils'; import { onDeviceManager } from './deviceManagerActions'; class PassphraseModule { @@ -42,6 +42,13 @@ class PassphraseModule { } public async confirmPassphraseOnEmu() { + if (getModelFromEnv() === 'T3W1') { + await TrezorUserEnvLink.pressYes(); + await TrezorUserEnvLink.pressYes(); + + return; + } + await TrezorUserEnvLink.swipeEmu('up'); await TrezorUserEnvLink.swipeEmu('up'); await TrezorUserEnvLink.pressYes(); diff --git a/suite-native/app/e2e/tests/coinEnabling.test.ts b/suite-native/app/e2e/tests/coinEnabling.test.ts index 2833ab57f6c5..0d93c526d069 100644 --- a/suite-native/app/e2e/tests/coinEnabling.test.ts +++ b/suite-native/app/e2e/tests/coinEnabling.test.ts @@ -3,15 +3,22 @@ import { conditionalDescribe } from '@suite-common/test-utils'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; import { onCoinEnabling } from '../pageObjects/coinEnablingActions'; import { onDeviceConnecting } from '../pageObjects/deviceConnectingActions'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onHome } from '../pageObjects/homeActions'; import { onSettings } from '../pageObjects/settingsActions'; import { onTabBar } from '../pageObjects/tabBarActions'; -import { disconnectTrezorUserEnv, openApp, prepareTrezorEmulator } from '../utils'; +import { disconnectTrezorUserEnv, getModelFromEnv, openApp, prepareTrezorEmulator } from '../utils'; conditionalDescribe(device.getPlatform() === 'android', 'Coin enabling', () => { beforeAll(async () => { await prepareTrezorEmulator(); await openApp({ newInstance: true, args: { preloadedState: onboardingCompletedState } }); + + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } }); afterAll(async () => { diff --git a/suite-native/app/e2e/tests/deeplinkPopup.test.ts b/suite-native/app/e2e/tests/deeplinkPopup.test.ts index 11d6d38b0942..d9ae92d2bf21 100644 --- a/suite-native/app/e2e/tests/deeplinkPopup.test.ts +++ b/suite-native/app/e2e/tests/deeplinkPopup.test.ts @@ -6,12 +6,18 @@ import { conditionalDescribe } from '@suite-common/test-utils'; import TrezorConnect from '@trezor/connect-mobile'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; -import { btcDiscoveryFinishedState } from '../fixtures/btcDiscoveryFinishedState'; +import { btcDiscoveryFinishedStateT3T1 } from '../fixtures/btcDiscoveryFinishedStateT3T1'; +import { btcDiscoveryFinishedStateT3W1 } from '../fixtures/btcDiscoveryFinishedStateT3W1'; import { deviceAutoEjectState } from '../fixtures/deviceAutoEjectState'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; +import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { appIsFullyLoaded, disconnectTrezorUserEnv, + getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator, @@ -40,7 +46,8 @@ const openUriScheme = (url: string, platformToOpen: 'android') => { const preloadedState = mergePreloadedReduxState( onboardingCompletedState, - btcDiscoveryFinishedState, + getModelFromEnv() === 'T3W1' ? btcDiscoveryFinishedStateT3W1 : btcDiscoveryFinishedStateT3T1, + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW deviceAutoEjectState, ); @@ -89,8 +96,14 @@ conditionalDescribe(device.getPlatform() === 'android', 'Deeplink connect popup. await prepareTrezorEmulator(); await restartApp(); - + + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } + await appIsFullyLoaded(); + }); afterAll(async () => { diff --git a/suite-native/app/e2e/tests/deviceOnboarding.test.ts b/suite-native/app/e2e/tests/deviceOnboarding.test.ts index d5f25755102a..4f0be04bd089 100644 --- a/suite-native/app/e2e/tests/deviceOnboarding.test.ts +++ b/suite-native/app/e2e/tests/deviceOnboarding.test.ts @@ -2,12 +2,15 @@ import { conditionalDescribe } from '@suite-common/test-utils'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; import { btcCoinEnabled } from '../fixtures/btcCoinEnabled'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onHome } from '../pageObjects/homeActions'; import { disconnectTrezorUserEnv, + getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator, @@ -16,14 +19,21 @@ import { } from '../utils'; const proceedToCreateOrRecoverCrossroads = async () => { + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } + await onDeviceOnboarding.waitForUninitializedDeviceLanding(); await onDeviceOnboarding.dismissTheUninitializedDeviceLanding(); await onDeviceOnboarding.skipFirmwareUpdate(); await TrezorUserEnvLink.pressYes(); - await onDeviceOnboarding.waitForDeviceAuthenticitySuccess(); - await onDeviceOnboarding.dismissDeviceAuthenticitySuccess(); + if (getModelFromEnv() !== 'T3W1') { // skip device authenticity check on T3W1 because we are using 2-main FW + await onDeviceOnboarding.waitForDeviceAuthenticitySuccess(); + await onDeviceOnboarding.dismissDeviceAuthenticitySuccess(); + } await TrezorUserEnvLink.pressYes(); @@ -42,7 +52,7 @@ const finishOnboardingFlow = async () => { const preloadedState = mergePreloadedReduxState( onboardingCompletedState, - deviceChecksEnabledState, + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW btcCoinEnabled, ); diff --git a/suite-native/app/e2e/tests/ejectWallets.test.ts b/suite-native/app/e2e/tests/ejectWallets.test.ts index 7e9d9e00c7ba..9cefa10ac825 100644 --- a/suite-native/app/e2e/tests/ejectWallets.test.ts +++ b/suite-native/app/e2e/tests/ejectWallets.test.ts @@ -1,15 +1,21 @@ import { conditionalDescribe } from '@suite-common/test-utils'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; +import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; import { regtestDiscoveryFinishedStateT3T1 } from '../fixtures/regtestDiscoveryFinishedStateT3T1'; +import { regtestDiscoveryFinishedStateT3W1 } from '../fixtures/regtestDiscoveryFinishedStateT3W1'; import { onAlertSheet } from '../pageObjects/alertSheetActions'; import { onDeviceManager } from '../pageObjects/deviceManagerActions'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onSettings } from '../pageObjects/settingsActions'; import { onTabBar } from '../pageObjects/tabBarActions'; import { appIsFullyLoaded, disconnectTrezorUserEnv, + getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator, @@ -19,7 +25,8 @@ import { const preloadedState = mergePreloadedReduxState( onboardingCompletedState, - regtestDiscoveryFinishedStateT3T1, + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW + getModelFromEnv() === 'T3T1' ? regtestDiscoveryFinishedStateT3T1 : regtestDiscoveryFinishedStateT3W1, ); const navigateToEjectWallets = async () => { @@ -38,6 +45,11 @@ conditionalDescribe(device.getPlatform() === 'android', 'Eject wallets', () => { await appIsFullyLoaded(); await prepareTrezorEmulator(); await restartApp(); + + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } }); afterEach(async () => { diff --git a/suite-native/app/e2e/tests/onboardAndConnect.test.ts b/suite-native/app/e2e/tests/onboardAndConnect.test.ts index a98d1e007d34..b0f956b190cf 100644 --- a/suite-native/app/e2e/tests/onboardAndConnect.test.ts +++ b/suite-native/app/e2e/tests/onboardAndConnect.test.ts @@ -1,8 +1,16 @@ import { conditionalDescribe } from '@suite-common/test-utils'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; +import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onCoinEnabling } from '../pageObjects/coinEnablingActions'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onOnboarding } from '../pageObjects/onboardingActions'; -import { disconnectTrezorUserEnv, openApp, prepareTrezorEmulator } from '../utils'; +import { disconnectTrezorUserEnv, getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator } from '../utils'; + +const preloadedState = mergePreloadedReduxState( + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW +); conditionalDescribe( device.getPlatform() === 'android', @@ -11,7 +19,12 @@ conditionalDescribe( beforeAll(async () => { await prepareTrezorEmulator(); - await openApp({ newInstance: true }); + await openApp({ + newInstance: true, + args: { + preloadedState, + }, + }); }); afterAll(async () => { @@ -21,6 +34,11 @@ conditionalDescribe( it('Navigate to dashboard', async () => { await onOnboarding.finishOnboarding(); + + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } await waitFor(element(by.id('@screen/CoinEnablingInit'))) .toBeVisible() diff --git a/suite-native/app/e2e/tests/passphraseFlow.test.ts b/suite-native/app/e2e/tests/passphraseFlow.test.ts index 4015d3281773..8011bd430f40 100644 --- a/suite-native/app/e2e/tests/passphraseFlow.test.ts +++ b/suite-native/app/e2e/tests/passphraseFlow.test.ts @@ -4,12 +4,18 @@ import { expect as detoxExpect } from 'detox'; import { conditionalDescribe } from '@suite-common/test-utils'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; +import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; import { regtestDiscoveryFinishedStateT3T1 } from '../fixtures/regtestDiscoveryFinishedStateT3T1'; +import { regtestDiscoveryFinishedStateT3W1 } from '../fixtures/regtestDiscoveryFinishedStateT3W1'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onPassphrase } from '../pageObjects/passphraseModule'; import { appIsFullyLoaded, disconnectTrezorUserEnv, + getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator, @@ -57,7 +63,8 @@ const expectNonEmptyWallet = async () => { const preloadedState = mergePreloadedReduxState( onboardingCompletedState, - regtestDiscoveryFinishedStateT3T1, + getModelFromEnv() === 'T3T1' ? regtestDiscoveryFinishedStateT3T1 : regtestDiscoveryFinishedStateT3W1, + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW ); conditionalDescribe(device.getPlatform() === 'android', 'passphrase flow', () => { @@ -138,6 +145,10 @@ conditionalDescribe(device.getPlatform() === 'android', 'passphrase flow', () => beforeEach(async () => { await prepareTrezorEmulator({ passphrase_protection: true }); await restartApp(); + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } await appIsFullyLoaded(); }); diff --git a/suite-native/app/e2e/tests/receive.test.ts b/suite-native/app/e2e/tests/receive.test.ts index d89582d049de..39329799ca08 100644 --- a/suite-native/app/e2e/tests/receive.test.ts +++ b/suite-native/app/e2e/tests/receive.test.ts @@ -1,15 +1,21 @@ import { conditionalDescribe } from '@suite-common/test-utils'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; -import { btcDiscoveryFinishedState } from '../fixtures/btcDiscoveryFinishedState'; +import { btcDiscoveryFinishedStateT3T1 } from '../fixtures/btcDiscoveryFinishedStateT3T1'; +import { btcDiscoveryFinishedStateT3W1 } from '../fixtures/btcDiscoveryFinishedStateT3W1'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; +import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; import { onAccountDetail } from '../pageObjects/accountDetailActions'; import { onAccountReceive } from '../pageObjects/accountReceiveActions'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onHome } from '../pageObjects/homeActions'; import { onMyAssets } from '../pageObjects/myAssetsActions'; import { onTabBar } from '../pageObjects/tabBarActions'; import { disconnectTrezorUserEnv, + getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator, @@ -18,7 +24,8 @@ import { const preloadedState = mergePreloadedReduxState( onboardingCompletedState, - btcDiscoveryFinishedState, + getModelFromEnv() === 'T3W1' ? btcDiscoveryFinishedStateT3W1 : btcDiscoveryFinishedStateT3T1, + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW ); conditionalDescribe(device.getPlatform() === 'android', 'Receive', () => { @@ -29,6 +36,10 @@ conditionalDescribe(device.getPlatform() === 'android', 'Receive', () => { }); await prepareTrezorEmulator(); await restartApp(); + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } }); afterAll(async () => { diff --git a/suite-native/app/e2e/tests/send.test.ts b/suite-native/app/e2e/tests/send.test.ts index 828544015611..49adaedbc2ff 100644 --- a/suite-native/app/e2e/tests/send.test.ts +++ b/suite-native/app/e2e/tests/send.test.ts @@ -1,9 +1,14 @@ import { conditionalDescribe } from '@suite-common/test-utils'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; +import { deviceChecksDisabledState } from '../fixtures/deviceChecksDisabledState'; +import { deviceChecksEnabledState } from '../fixtures/deviceChecksEnabledState'; import { onboardingCompletedState } from '../fixtures/onboardingCompletedState'; import { regtestDiscoveryFinishedStateT3T1 } from '../fixtures/regtestDiscoveryFinishedStateT3T1'; +import { regtestDiscoveryFinishedStateT3W1 } from '../fixtures/regtestDiscoveryFinishedStateT3W1'; import { onAccountDetail } from '../pageObjects/accountDetailActions'; +import { onDeviceOnboarding } from '../pageObjects/deviceOnboardingActions'; +import { onDevicePrompt } from '../pageObjects/devicePromptActions'; import { onHome } from '../pageObjects/homeActions'; import { onMyAssets } from '../pageObjects/myAssetsActions'; import { onSendAddressReview } from '../pageObjects/send/sendAddressReviewActions'; @@ -14,10 +19,12 @@ import { onTabBar } from '../pageObjects/tabBarActions'; import { appIsFullyLoaded, disconnectTrezorUserEnv, + getModelFromEnv, mergePreloadedReduxState, openApp, prepareTrezorEmulator, restartApp, + wipeAppData, } from '../utils'; const SEND_FORM_ERROR_MESSAGES = { @@ -66,13 +73,12 @@ const signTransactionAndSendIt = async () => { const preloadedState = mergePreloadedReduxState( onboardingCompletedState, - regtestDiscoveryFinishedStateT3T1, + getModelFromEnv() === 'T3T1' ? regtestDiscoveryFinishedStateT3T1 : regtestDiscoveryFinishedStateT3W1, + getModelFromEnv() === 'T3W1' ? deviceChecksDisabledState : deviceChecksEnabledState, // skip device checks on T3W1 because we are using 2-main FW ); conditionalDescribe(device.getPlatform() === 'android', 'Send transaction flow.', () => { beforeAll(async () => { - await openApp({ newInstance: true, args: { preloadedState } }); - await TrezorUserEnvLink.sendToAddressAndMineBlock({ address: 'bcrt1q34up3cga3fkmph47t22mpk5d0xxj3ppghph9da', btc_amount: INITIAL_ACCOUNT_BALANCE, @@ -80,8 +86,13 @@ conditionalDescribe(device.getPlatform() === 'android', 'Send transaction flow.' }); beforeEach(async () => { + await openApp({ newInstance: true, args: { preloadedState } }); await prepareTrezorEmulator(); await restartApp(); + if (getModelFromEnv() === 'T3W1') { + await onDevicePrompt.allowConnectToTrezor(); + await onDeviceOnboarding.enterTHPPairingCode(); + } await appIsFullyLoaded(); await onHome.waitForScreen(); @@ -92,6 +103,10 @@ conditionalDescribe(device.getPlatform() === 'android', 'Send transaction flow.' await onAccountDetail.openSend(); await onSendOutputsForm.waitForScreen(); }); + + afterEach(async () => { + await wipeAppData(); + }); afterAll(async () => { await disconnectTrezorUserEnv(); diff --git a/suite-native/app/e2e/utils.ts b/suite-native/app/e2e/utils.ts index 4aae7b2ee55e..0da06c8860c1 100644 --- a/suite-native/app/e2e/utils.ts +++ b/suite-native/app/e2e/utils.ts @@ -143,7 +143,7 @@ export const appIsFullyLoaded = async () => { .withTimeout(35000); }; -function getModelFromEnv(): Model { +export function getModelFromEnv(): Model { const envValue = process.env.EMULATOR_MODEL as Model; return MODELS.includes(envValue) ? envValue : 'T3T1'; @@ -156,6 +156,16 @@ export type PrepareTrezorEmulatorProps = { version?: string; }; +const getFwVersion = (model: Model, version: string | undefined) => { + if (model === 'T3W1') { + return '2-main'; // At this time only this firmware works with T3W1 + } else { + const modelSupportedFirmwares = TrezorUserEnvLink?.firmwares?.[model] || []; + + return (version && modelSupportedFirmwares.find(v => v.replace('-arm', '') === version)) || '2-latest'; + } +}; + export const prepareTrezorEmulator = async ({ version, seed = MNEMONICS.mnemonic_immune, @@ -164,11 +174,8 @@ export const prepareTrezorEmulator = async ({ }: PrepareTrezorEmulatorProps = {}) => { if (platform === 'android') { // Prepare Trezor device for test scenario - const modelSupportedFirmwares = TrezorUserEnvLink?.firmwares?.[model] || []; + const fwVersion = getFwVersion(model, version); - const fwVersion = - (version && modelSupportedFirmwares.find(v => v.replace('-arm', '') === version)) || - '2-latest'; await TrezorUserEnvLink.disconnect(); await TrezorUserEnvLink.connect(); // start with latest officially released firmware (necessary to pass the firmware checks) diff --git a/suite-native/thp/src/components/SecurityCodeInput.tsx b/suite-native/thp/src/components/SecurityCodeInput.tsx index d1ba202bc28a..069adde43e09 100644 --- a/suite-native/thp/src/components/SecurityCodeInput.tsx +++ b/suite-native/thp/src/components/SecurityCodeInput.tsx @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Platform, Pressable, TextInput } from 'react-native'; import { Box, HStack, Text } from '@suite-native/atoms'; +import { isDetoxTestBuild } from '@suite-native/config'; import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; type DigitBoxProps = { @@ -97,7 +98,16 @@ export const SecurityCodeInput = ({ length, onSubmit }: SecurityCodeInputProps) onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)} onKeyPress={e => onKeyPress(e.nativeEvent.key)} - style={applyStyle(textInputStyle)} + onChangeText={text => { + if (!isDetoxTestBuild()) { + return; + } + const digits = text.replace(/\D/g, '').slice(0, length); + setCode(digits); + onSubmit(digits); + }} + style={isDetoxTestBuild() ? applyStyle(prepareNativeStyle(_ => ({}))) : applyStyle(textInputStyle)} + testID="@thpSecurityCode/Input" /> {Array.from({ length }).map((_, i) => ( @@ -105,7 +115,6 @@ export const SecurityCodeInput = ({ length, onSubmit }: SecurityCodeInputProps) key={i} value={code.at(i)} isFocused={isFocused && i === code.length} - testID={`@thpSecurityCode/Input/${i}`} /> ))}