From 4c5bd49b206d0d77e710afa881a78604dc7ca7d4 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Ortiz karliatto Date: Fri, 4 Oct 2024 14:43:54 +0200 Subject: [PATCH] test(suite-native): new deeplinkPopup test --- .../app/e2e/tests/deeplinkPopup.test.ts | 150 ++++++++++++++++++ suite-native/app/package.json | 1 + suite-native/app/tsconfig.json | 5 +- yarn.lock | 3 +- 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 suite-native/app/e2e/tests/deeplinkPopup.test.ts diff --git a/suite-native/app/e2e/tests/deeplinkPopup.test.ts b/suite-native/app/e2e/tests/deeplinkPopup.test.ts new file mode 100644 index 00000000000..164fadfaa95 --- /dev/null +++ b/suite-native/app/e2e/tests/deeplinkPopup.test.ts @@ -0,0 +1,150 @@ +import http from 'http'; +import { exec } from 'child_process'; +// `expect` keyword is already used by jest. +import { expect as detoxExpect } from 'detox'; + +import { TrezorUserEnvLink, MNEMONICS } from '@trezor/trezor-user-env-link'; +import TrezorConnect from '@trezor/connect-deeplink'; + +import { openApp } from '../utils'; +import { onOnboarding } from '../pageObjects/onboardingActions'; +import { onCoinEnablingInit } from '../pageObjects/coinEnablingActions'; + +const TREZOR_DEVICE_LABEL = 'Trezor T - Tester'; +const platform = device.getPlatform(); + +let server: http.Server | undefined; + +function openUriScheme(url: string, platformToOpen: 'android') { + const command = `npx uri-scheme open '${url.replace(/'/g, '')}' --${platformToOpen}`; + + exec(command, (err, stdout, stderr) => { + if (err) { + console.error(err); + + return; + } + // eslint-disable-next-line no-console + console.info(stdout); + console.error(stderr); + }); +} + +describe('Deeplink connect popup.', () => { + beforeAll(async () => { + server = http.createServer((req, res) => { + if (req.url) { + const url = new URL(req.url, `http://localhost:8080`); + TrezorConnect.handleDeeplink(url.href); + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Callback URL received successfully!\n'); + } + }); + + server.listen(8080, 'localhost', () => { + // eslint-disable-next-line no-console + console.info('Server running at http://localhost:8080/'); + }); + + if (platform === 'android') { + // Prepare Trezor device for test scenario and turn it off. + await TrezorUserEnvLink.disconnect(); + await TrezorUserEnvLink.connect(); + await TrezorUserEnvLink.startEmu({ wipe: true }); + await TrezorUserEnvLink.setupEmu({ + label: TREZOR_DEVICE_LABEL, + mnemonic: MNEMONICS.mnemonic_immune, + }); + await TrezorUserEnvLink.startBridge(); + await TrezorUserEnvLink.stopEmu(); + await TrezorConnect.init({ + manifest: { + email: 'developer@xyz.com', + appUrl: 'http://your.application.com', + }, + deeplinkOpen: url => { + openUriScheme(url, 'android'); + }, + deeplinkCallbackUrl: 'http://localhost:8080/connect/', + }); + } + + await openApp({ newInstance: true }); + }); + + afterAll(async () => { + if (platform === 'android') { + await TrezorUserEnvLink.stopEmu(); + } + await new Promise(resolve => { + if (server) { + server.close(() => { + resolve(null); + }); + } + }); + await device.terminateApp(); + }); + + it('Navigate to dashboard', async () => { + await onOnboarding.finishOnboarding(); + + if (platform === 'android') { + await TrezorUserEnvLink.startEmu(); + + await waitFor(element(by.id('@screen/CoinEnablingInit'))) + .toBeVisible() + .withTimeout(10000); + + await onCoinEnablingInit.waitForBtcToBeVisible(); + + await onCoinEnablingInit.enableNetwork('btc'); + // TODO: I don't understand why without eth the part after does not complete. + await onCoinEnablingInit.enableNetwork('eth'); + + await onCoinEnablingInit.save(); + + await waitFor(element(by.id('skip-view-only-mode'))) + .toBeVisible() + .withTimeout(60000); // communication between connected Trezor and app takes some time. + + await element(by.id('skip-view-only-mode')).tap(); + + await detoxExpect(element(by.id('@home/portfolio/graph'))); // discovery finished and graph is visible + + const promise = TrezorConnect.getAddress({ + path: "m/49'/0'/0'/0/0", + coin: 'btc', + }); + + await element(by.id('@popup/deeplink-info')); + + await waitFor(element(by.id('@popup/call-device'))) + .toBeVisible() + .withTimeout(10 * 1000); + await element(by.id('@popup/call-device')).tap(); + + await TrezorUserEnvLink.pressYes(); + + const response = await promise; + + const expectedResponse = { + id: 1, + payload: { + path: [49, 0, 0, 0, 0], + serializedPath: 'm/49/0/0/0/0', + address: '3J7UQSLAaFh1nkUomVdm8ArifPEvYfNr1o', + }, + success: true, + }; + + await new Promise((resolve, reject) => { + if (JSON.stringify(response) === JSON.stringify(expectedResponse)) { + return resolve(null); + } + reject(new Error('Result does not match expected.')); + }); + } + }); +}); diff --git a/suite-native/app/package.json b/suite-native/app/package.json index dd06171a07f..ab1748d28e6 100644 --- a/suite-native/app/package.json +++ b/suite-native/app/package.json @@ -118,6 +118,7 @@ "@babel/plugin-transform-export-namespace-from": "^7.23.4", "@config-plugins/detox": "^8.0.0", "@react-native/babel-preset": "^0.75.2", + "@trezor/connect-deeplink": "workspace:^", "@types/jest": "^29.5.12", "@types/node": "^20.11.24", "babel-plugin-transform-inline-environment-variables": "^0.4.4", diff --git a/suite-native/app/tsconfig.json b/suite-native/app/tsconfig.json index 5c5b2a56ff8..d749fb78a91 100644 --- a/suite-native/app/tsconfig.json +++ b/suite-native/app/tsconfig.json @@ -72,7 +72,10 @@ "path": "../../packages/react-native-usb" }, { "path": "../../packages/styles" }, - { "path": "../../packages/theme" } + { "path": "../../packages/theme" }, + { + "path": "../../packages/connect-deeplink" + } ], "include": [".", "**.json"] } diff --git a/yarn.lock b/yarn.lock index cec1ceb0070..b83cb670e38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9598,6 +9598,7 @@ __metadata: "@suite-native/toasts": "workspace:*" "@suite-native/transactions": "workspace:*" "@trezor/connect": "workspace:*" + "@trezor/connect-deeplink": "workspace:^" "@trezor/react-native-usb": "workspace:*" "@trezor/styles": "workspace:*" "@trezor/theme": "workspace:*" @@ -11237,7 +11238,7 @@ __metadata: languageName: unknown linkType: soft -"@trezor/connect-deeplink@workspace:*, @trezor/connect-deeplink@workspace:packages/connect-deeplink": +"@trezor/connect-deeplink@workspace:*, @trezor/connect-deeplink@workspace:^, @trezor/connect-deeplink@workspace:packages/connect-deeplink": version: 0.0.0-use.local resolution: "@trezor/connect-deeplink@workspace:packages/connect-deeplink" dependencies: