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

[QAA-331][Detox] Implement CLI in Speculos test #8420

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@types/command-line-args": "5.2.3",
"@types/cors": "2.8.17",
"@types/express": "4.17.21",
"@types/invariant": "2.2.37",
"@types/lodash": "4.17.7",
"@types/node": "20.12.12",
"@types/pako": "2.0.3",
Expand Down
16 changes: 11 additions & 5 deletions apps/cli/src/live-common-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,16 @@ registerTransportModule({
disconnect: () => Promise.resolve(),
});

if (process.env.DEVICE_PROXY_URL) {
const Tr = createTransportHttp(process.env.DEVICE_PROXY_URL.split("|"));
const {
SPECULOS_API_PORT,
SPECULOS_APDU_PORT,
SPECULOS_BUTTON_PORT,
SPECULOS_HOST,
DEVICE_PROXY_URL,
} = process.env;

if (DEVICE_PROXY_URL) {
const Tr = createTransportHttp(DEVICE_PROXY_URL.split("|"));
registerTransportModule({
id: "http",
open: () =>
Expand All @@ -78,8 +86,6 @@ if (process.env.DEVICE_PROXY_URL) {
});
}

const { SPECULOS_API_PORT, SPECULOS_APDU_PORT, SPECULOS_BUTTON_PORT, SPECULOS_HOST } = process.env;

if (SPECULOS_API_PORT) {
registerSpeculosTransport(parseInt(SPECULOS_API_PORT, 10));
} else if (SPECULOS_APDU_PORT) {
Expand Down Expand Up @@ -146,7 +152,7 @@ export function registerSpeculosTransport(apiPort: number) {

LiveConfig.setConfig(liveConfig);

if (!process.env.CI && !SPECULOS_API_PORT) {
if (!process.env.CI && !SPECULOS_API_PORT && !DEVICE_PROXY_URL) {
init();
}

Expand Down
3 changes: 1 addition & 2 deletions apps/ledger-live-mobile/e2e/page/common.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ export default class CommonPage {
await new DeviceAction(nano).accessManager();
}

async addSpeculos(nanoApp: string) {
async addSpeculos(nanoApp: string, speculosAddress = "localhost") {
const proxyPort = await bridge.findFreePort();
const speculosAddress = "localhost";
const speculosPort = await launchSpeculos(nanoApp, proxyPort);
await launchProxy(proxyPort, speculosAddress, speculosPort);
await bridge.addKnownSpeculos(`${proxyAddress}:${proxyPort}`);
Expand Down
55 changes: 50 additions & 5 deletions apps/ledger-live-mobile/e2e/page/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,26 @@ 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";
import { lastValueFrom, Observable } from "rxjs";
import path from "path";
import fs from "fs";
import { getEnv } from "@ledgerhq/live-env";

type ApplicationOptions = {
speculosApp?: AppInfos;
cliCommands?: (Observable<unknown> | Promise<unknown> | string)[];
userdata?: string;
knownDevices?: DeviceLike[];
testAccounts?: Account[];
};

export const getUserdataPath = (userdata: string) => {
return path.resolve("e2e", "userdata", `${userdata}.json`);
};

export class Application {
public userdataSpeculos: string | undefined = undefined;
public userdataPath: string | undefined = undefined;
public account = new AccountPage();
public accounts = new AccountsPage();
public addAccount = new AddAccountDrawer();
Expand Down Expand Up @@ -65,13 +76,47 @@ export class Application {
public transfertMenu = new TransfertMenuDrawer();
public walletTabNavigator = new WalletTabNavigatorPage();

static async init({ speculosApp, userdata, knownDevices, testAccounts }: ApplicationOptions) {
const app = new Application();
userdata && (await loadConfig(userdata, true));
constructor() {
if (!getEnv("MOCK")) {
// Create a temporary userdata file for Speculos tests
const originalUserdata = "onboardingcompleted";
this.userdataSpeculos = `temp-userdata-${Date.now()}`;
this.userdataPath = getUserdataPath(this.userdataSpeculos);
const originalFilePath = getUserdataPath(originalUserdata);
fs.copyFileSync(originalFilePath, this.userdataPath);
}
}

async init({
speculosApp,
cliCommands,
userdata,
knownDevices,
testAccounts,
}: ApplicationOptions) {
let proxyPort = 0;
if (speculosApp) {
proxyPort = await this.common.addSpeculos(speculosApp.name);
process.env.DEVICE_PROXY_URL = `ws://localhost:${proxyPort}`;
require("@ledgerhq/live-cli/src/live-common-setup");
}

if (cliCommands?.length) {
await Promise.all(
cliCommands.map(async cmd => {
const result = cmd instanceof Observable ? await lastValueFrom(cmd) : await cmd;
// eslint-disable-next-line no-console
console.log("CLI result: ", result);
}),
);
}

if (this.userdataSpeculos) await loadConfig(this.userdataSpeculos, true);
else userdata && (await loadConfig(userdata, true));
knownDevices && (await loadBleState({ knownDevices }));
testAccounts && (await loadAccounts(testAccounts));
speculosApp && (await app.common.addSpeculos(speculosApp.name));

return app;
const userdataSpeculosPath = getUserdataPath(this.userdataSpeculos!);
if (fs.existsSync(userdataSpeculosPath)) fs.unlinkSync(userdataSpeculosPath);
}
}
9 changes: 8 additions & 1 deletion apps/ledger-live-mobile/e2e/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ 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");

if (process.env.MOCK == "0") {
setEnv("MOCK", "");
process.env.MOCK = "";
} else {
setEnv("MOCK", "1");
process.env.MOCK = "1";
}

beforeAll(
async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { knownDevices } from "../../models/devices";
import DeviceAction from "../../models/DeviceAction";
import { Application } from "../../page";

let app: Application;
const app = new Application();
let deviceAction: DeviceAction;

const testedCurrency = "bitcoin";
Expand All @@ -11,7 +11,7 @@ const knownDevice = knownDevices.nanoX;

describe("Add account from modal", () => {
beforeAll(async () => {
app = await Application.init({
await app.init({
userdata: "onboardingcompleted",
knownDevices: [knownDevice],
});
Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/deeplinks.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Application } from "../page";
import { knownDevices } from "../models/devices";

let app: Application;
const app = new Application();

const ethereumLong = "ethereum";
const bitcoinLong = "bitcoin";
Expand All @@ -11,7 +11,7 @@ const bobaLong = "boba";
$TmsLink("B2CQA-1837");
describe("DeepLinks Tests", () => {
beforeAll(async () => {
app = await Application.init({
await app.init({
userdata: "1AccountBTC1AccountETHReadOnlyFalse",
knownDevices: [knownDevices.nanoX],
});
Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/delegate/cosmos.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Application } from "../../page";
import DeviceAction from "../../models/DeviceAction";
import BigNumber from "bignumber.js";

let app: Application;
const app = new Application();
let deviceAction: DeviceAction;

const testedCurrency = "cosmos";
Expand All @@ -20,7 +20,7 @@ const knownDevice = knownDevices.nanoX;

describe("Cosmos delegate flow", () => {
beforeAll(async () => {
app = await Application.init({
await app.init({
userdata: "onboardingcompleted",
knownDevices: [knownDevice],
testAccounts: [testAccount],
Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/languageChange.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Application } from "../page";

let app: Application;
const app = new Application();

const langButtonText = [
{ lang: "Français", localization: "Général" },
Expand All @@ -26,7 +26,7 @@ const verifyLanguageCanBeChanged = (l10n: { lang: string; localization: string }
$TmsLink("B2CQA-2344");
describe("Change Language", () => {
beforeAll(async () => {
app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" });
await app.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" });
await app.portfolio.waitForPortfolioPageToLoad();
});

Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { knownDevices } from "../models/devices";
import { deviceInfo155 as deviceInfo } from "@ledgerhq/live-common/apps/mock";
import { Application } from "../page";

let app: Application;
const app = new Application();
let deviceAction: DeviceAction;

const appDesc = ["Bitcoin", "Tron", "Litecoin", "Ethereum", "XRP", "Stellar"];
Expand All @@ -12,7 +12,7 @@ const knownDevice = knownDevices.nanoX;

describe("Test My Ledger", () => {
beforeAll(async () => {
app = await Application.init({ userdata: "onboardingcompleted" });
await app.init({ userdata: "onboardingcompleted" });
deviceAction = new DeviceAction(knownDevice);

await app.portfolio.waitForPortfolioPageToLoad();
Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/market.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Application } from "../page";

let app: Application;
const app = new Application();
const asset = "Ethereum (ETH)";

describe("Market page for user with no device", () => {
beforeAll(async () => {
app = await Application.init({ userdata: "1accountEth" });
await app.init({ userdata: "1accountEth" });
await app.portfolio.waitForPortfolioPageToLoad();
});

Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/nftGallery.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { tapByElement } from "../helpers";
import { Application } from "../page";

let app: Application;
const app = new Application();
const accountCurrency = "ethereum";

// To-Do Fix NFT not available in account
describe.skip("NFT Gallery screen", () => {
beforeAll(async () => {
app = await Application.init({ userdata: "1Account1NFTNotSpam" });
await app.init({ userdata: "1Account1NFTNotSpam" });

await app.portfolio.waitForPortfolioPageToLoad();
await app.nftGallery.openViaDeeplink();
Expand Down
6 changes: 1 addition & 5 deletions apps/ledger-live-mobile/e2e/specs/onboarding.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@ import { device } from "detox";
import { isAndroid, launchApp } from "../helpers";
import { Application } from "../page";

let app: Application;
const app = new Application();

let isFirstTest = true;

describe("Onboarding", () => {
beforeAll(() => {
app = new Application();
});

beforeEach(async () => {
if (!isFirstTest) {
await device.uninstallApp();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { device } from "detox";
import { Application } from "../page";

let app: Application;
const app = new Application();

describe("Onboarding - Read Only", () => {
beforeAll(() => {
app = new Application();
});

$TmsLink("B2CQA-1752");
it("is able to buy a nano from the onboarding flow", async () => {
await app.onboarding.startOnboarding();
Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/password.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { device } from "detox";
import { Application } from "../page";

let app: Application;
const app = new Application();

const CORRECT_PASSWORD = "passWORD$123!";

describe("Password Lock Screen", () => {
beforeAll(async () => {
app = await Application.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" });
await app.init({ userdata: "1AccountBTC1AccountETHReadOnlyFalse" });
await app.portfolio.waitForPortfolioPageToLoad();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { knownDevices } from "../../models/devices";
import { getCryptoCurrencyById } from "@ledgerhq/live-common/currencies/index";
import { Application } from "../../page";

let app: Application;
const app = new Application();
let deviceAction: DeviceAction;
let first = true;
const knownDevice = knownDevices.nanoX;
Expand All @@ -12,7 +12,7 @@ $TmsLink("B2CQA-651");
$TmsLink("B2CQA-1854");
describe("Receive different currency", () => {
beforeAll(async () => {
app = await Application.init({
await app.init({
userdata: "onboardingcompleted",
knownDevices: [knownDevice],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import DeviceAction from "../../models/DeviceAction";
import { knownDevices } from "../../models/devices";
import { Application } from "../../page";

let app: Application;
const app = new Application();
let deviceAction: DeviceAction;
const btcReceiveAddress = "173ej2furpaB8mTtN5m9829MPGMD7kCgSPx";
let first = true;
const knownDevice = knownDevices.nanoX;

describe("Receive Flow", () => {
beforeAll(async () => {
app = await Application.init({
await app.init({
userdata: "EthAccountXrpAccountReadOnlyFalse",
knownDevices: [knownDevice],
});
Expand Down
4 changes: 2 additions & 2 deletions apps/ledger-live-mobile/e2e/specs/send/currencies.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "../../models/currencies";
import { Application } from "../../page";

let app: Application;
const app = new Application();
let deviceAction: DeviceAction;

let first = true;
Expand All @@ -35,7 +35,7 @@ const knownDevice = knownDevices.nanoX;
$TmsLink("B2CQA-1823");
describe("Send flow", () => {
beforeAll(async () => {
app = await Application.init({
await app.init({
userdata: "onboardingcompleted",
knownDevices: [knownDevice],
testAccounts: testAccounts,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Application } from "../../page";

let app: Application;
const app = new Application();

const currencies = [
{ currency: "bitcoin", nanoApp: "Bitcoin", tmsLink: "B2CQA-101" },
Expand All @@ -9,7 +9,7 @@ const currencies = [

describe("Add accounts", () => {
beforeAll(async () => {
app = await Application.init({ userdata: "onboardingcompleted" });
await app.init({ userdata: "onboardingcompleted" });
await app.portfolio.waitForPortfolioPageToLoad();
});

Expand Down
Loading
Loading