Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: test: deeplink connect native #14667

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/test-suite-native-e2e-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ jobs:
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Reverse port for deeplink test server
run: |
adb reverse tcp:8080 tcp:8080

- name: Run Detox E2E Android tests
uses: reactivecircus/android-emulator-runner@v2
env:
Expand Down
2 changes: 2 additions & 0 deletions packages/trezor-user-env-link/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export const MNEMONICS = {
mnemonic_12: 'alcohol woman abuse must during monitor noble actual mixed trade anger aisle',
mnemonic_abandon:
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
// Contains only one BTC account with a single transaction to make the discovery as fast as possible.
mnemonic_immune: 'immune enlist rule measure fan swarm mandate track point menu security fan',
};

export const DEFAULT_BRIDGE_VERSION = '2.0.33';
Expand Down
150 changes: 150 additions & 0 deletions suite-native/app/e2e/tests/deeplinkPopup.test.ts
Original file line number Diff line number Diff line change
@@ -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: '[email protected]',
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.'));
});
}
});
});
6 changes: 2 additions & 4 deletions suite-native/app/e2e/tests/onboardAndConnect.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// `expect` keyword is already used by jest.
import { expect as detoxExpect } from 'detox';

import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link';
import { MNEMONICS, TrezorUserEnvLink } from '@trezor/trezor-user-env-link';

import { openApp } from '../utils';
import { onOnboarding } from '../pageObjects/onboardingActions';
import { onCoinEnablingInit } from '../pageObjects/coinEnablingActions';

const TREZOR_DEVICE_LABEL = 'Trezor T - Tester';
// Contains only one BTC account with a single transaction to make the discovery as fast as possible.
const SIMPLE_SEED = 'immune enlist rule measure fan swarm mandate track point menu security fan';
const platform = device.getPlatform();

describe('Go through onboarding and connect Trezor.', () => {
Expand All @@ -21,7 +19,7 @@ describe('Go through onboarding and connect Trezor.', () => {
await TrezorUserEnvLink.startEmu({ wipe: true });
await TrezorUserEnvLink.setupEmu({
label: TREZOR_DEVICE_LABEL,
mnemonic: SIMPLE_SEED,
mnemonic: MNEMONICS.mnemonic_immune,
});
await TrezorUserEnvLink.startBridge();
await TrezorUserEnvLink.stopEmu();
Expand Down
1 change: 1 addition & 0 deletions suite-native/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 4 additions & 1 deletion suite-native/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@
"path": "../../packages/react-native-usb"
},
{ "path": "../../packages/styles" },
{ "path": "../../packages/theme" }
{ "path": "../../packages/theme" },
{
"path": "../../packages/connect-deeplink"
}
],
"include": [".", "**.json"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const ConnectPopupScreen = ({
}

return (
<VStack spacing="sp8" alignItems="center">
<VStack testID="@popup/deeplink-info" spacing="sp8" alignItems="center">
<Text variant="titleSmall">
{method.confirmation?.label ?? method.info}
</Text>
Expand All @@ -122,7 +122,7 @@ export const ConnectPopupScreen = ({
>
<Translation id="moduleConnectPopup.areYouSureMessage" />
</Text>
<Button onPress={callDevice}>
<Button testID="@popup/call-device" onPress={callDevice}>
{method.confirmation?.customConfirmButton?.label ?? (
<Translation id="moduleConnectPopup.confirm" />
)}
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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:*"
Expand Down Expand Up @@ -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:
Expand Down
Loading