diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index dc57326..d2ea92b 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -106,6 +106,10 @@ services: - '--noseedbackup' - '--alias=lnd' - '--externalip=${LND_EXTERNAL_IP:-127.0.0.1}' + # LND issues its own cert on first start, covering only 127.0.0.1, ::1 and + # its container address. gRPC and REST verify the hostname, so reaching it + # from another machine needs that address in the SAN list. + - '--tlsextraip=${LND_EXTERNAL_IP:-127.0.0.1}' - '--bitcoin.active' - '--bitcoin.regtest' - '--bitcoin.node=bitcoind' diff --git a/test/helpers/setup.ts b/test/helpers/setup.ts index 77b53c0..5ba8e5c 100644 --- a/test/helpers/setup.ts +++ b/test/helpers/setup.ts @@ -42,11 +42,25 @@ export function grantIOSCameraPermission(appIdParam?: string) { } } +export async function activateAppWithEnv(appId: string) { + // processArguments in the session capabilities only apply to the first launch, + // so a relaunch would lose E2E_LOCAL_HOST and the app would fall back to the + // Info.plist value baked in at build time. + if (driver.isIOS && process.env.E2E_LOCAL_HOST) { + await driver.execute('mobile: launchApp', { + bundleId: appId, + environment: { E2E_LOCAL_HOST: process.env.E2E_LOCAL_HOST }, + }); + return; + } + await driver.activateApp(appId); +} + export async function launchFreshApp() { const appId = getAppId(); await driver.terminateApp(appId); - await driver.activateApp(appId); + await activateAppWithEnv(appId); await sleep(3000); } @@ -62,7 +76,7 @@ export async function reinstallApp() { resetBootedIOSKeychain(); await driver.installApp(appPath); grantIOSCameraPermission(appId); - await driver.activateApp(appId); + await activateAppWithEnv(appId); } export function getRnAppPath(): string { @@ -92,7 +106,7 @@ export async function reinstallAppFromPath(appPath: string, appId: string = getA resetBootedIOSKeychain(); await driver.installApp(appPath); grantIOSCameraPermission(appId); - await driver.activateApp(appId); + await activateAppWithEnv(appId); } /** diff --git a/test/specs/migration.e2e.ts b/test/specs/migration.e2e.ts index 6dc165f..b41e7e5 100644 --- a/test/specs/migration.e2e.ts +++ b/test/specs/migration.e2e.ts @@ -29,6 +29,7 @@ import { grantIOSCameraPermission, reinstallAppFromPath, resetBootedIOSKeychain, + activateAppWithEnv, } from '../helpers/setup'; import { getAppId } from '../helpers/constants'; import initElectrum, { ElectrumClient } from '../helpers/electrum'; @@ -172,7 +173,7 @@ describe('@migration - Migration from legacy RN app to native app', () => { console.info(`→ Installing native app from: ${getNativeAppPath()}`); await driver.installApp(getNativeAppPath()); grantIOSCameraPermission(); - await driver.activateApp(getAppId()); + await activateAppWithEnv(getAppId()); // Restore wallet with mnemonic (uses custom flow to handle backup sheet) await restoreWallet(mnemonic!, { @@ -197,7 +198,7 @@ describe('@migration - Migration from legacy RN app to native app', () => { console.info(`→ Installing native app on top of RN: ${getNativeAppPath()}`); await driver.installApp(getNativeAppPath()); grantIOSCameraPermission(); - await driver.activateApp(getAppId()); + await activateAppWithEnv(getAppId()); // Handle migration flow await handleMigrationFlow({ withSweep: false }); @@ -217,7 +218,7 @@ describe('@migration - Migration from legacy RN app to native app', () => { console.info(`→ Installing native app on top of RN: ${getNativeAppPath()}`); await driver.installApp(getNativeAppPath()); grantIOSCameraPermission(); - await driver.activateApp(getAppId()); + await activateAppWithEnv(getAppId()); // Handle migration flow await handleMigrationFlow({ withSweep: false }); @@ -239,7 +240,7 @@ describe('@migration - Migration from legacy RN app to native app', () => { console.info(`→ Installing native app on top of RN: ${getNativeAppPath()}`); await driver.installApp(getNativeAppPath()); grantIOSCameraPermission(); - await driver.activateApp(getAppId()); + await activateAppWithEnv(getAppId()); // Handle migration flow await handleMigrationFlow({ withSweep: false }); diff --git a/test/specs/receive-ln-payments.e2e.ts b/test/specs/receive-ln-payments.e2e.ts index cf5aa5d..9931634 100644 --- a/test/specs/receive-ln-payments.e2e.ts +++ b/test/specs/receive-ln-payments.e2e.ts @@ -22,6 +22,7 @@ import { } from '../helpers/actions'; import { payInvoice } from '../helpers/regtest'; import { getAppId } from '../helpers/constants'; +import { activateAppWithEnv } from '../helpers/setup'; const PAYMENT_COUNT = Number(process.env.PAYMENT_COUNT || '21'); const PAYMENT_AMOUNT = Number(process.env.PAYMENT_AMOUNT || '10'); @@ -39,7 +40,7 @@ function extractLightningInvoice(uri: string): string { describe('Receive LN payments (utility)', () => { before(async () => { const appId = getAppId(); - await driver.activateApp(appId); + await activateAppWithEnv(appId); await sleep(3000); }); diff --git a/wdio.conf.ts b/wdio.conf.ts index dc12f66..8bcdc16 100644 --- a/wdio.conf.ts +++ b/wdio.conf.ts @@ -18,6 +18,11 @@ const appiumNewCommandTimeout = Number.parseInt( process.env.APPIUM_NEW_COMMAND_TIMEOUT ?? '300', 10 ); +const wdaLaunchTimeout = Number.parseInt(process.env.WDA_LAUNCH_TIMEOUT ?? '300000', 10); +const connectionRetryTimeout = Number.parseInt( + process.env.WDIO_CONNECTION_RETRY_TIMEOUT ?? '360000', + 10 +); export const config: WebdriverIO.Config = { // @@ -108,8 +113,8 @@ export const config: WebdriverIO.Config = { // 🩹 Stability improvements 'appium:newCommandTimeout': 300, - 'appium:wdaLaunchTimeout': 300000, - 'appium:wdaConnectionTimeout': 300000, + 'appium:wdaLaunchTimeout': wdaLaunchTimeout, + 'appium:wdaConnectionTimeout': wdaLaunchTimeout, 'appium:wdaStartupRetries': 3, 'appium:wdaStartupRetryInterval': 5000, }, @@ -122,7 +127,7 @@ export const config: WebdriverIO.Config = { // Define all options that are relevant for the WebdriverIO instance here // // Level of logging verbosity: trace | debug | info | warn | error | silent - logLevel: 'warn', + logLevel: (process.env.WDIO_LOG_LEVEL as WebdriverIO.Config['logLevel']) ?? 'warn', // // Set specific log levels per logger // loggers: @@ -153,8 +158,8 @@ export const config: WebdriverIO.Config = { // // Default timeout in milliseconds for request // if browser driver or grid doesn't send response - // Must be >= wdaLaunchTimeout (300000) to allow WDA time to start - connectionRetryTimeout: 360000, + // Must be >= wdaLaunchTimeout to allow WDA time to start + connectionRetryTimeout, // // Default request retries count connectionRetryCount: 3, @@ -163,7 +168,11 @@ export const config: WebdriverIO.Config = { // Services take over a specific job you don't want to take care of. They enhance // your test setup with almost no effort. Unlike plugins, they don't add new // commands. Instead, they hook themselves up into the test process. - services: ['appium'], + services: [ + // Appium's own log is the only place that says whether WDA is building, + // launching or failing to connect. + ['appium', { logPath: process.env.APPIUM_LOG_PATH ?? './artifacts' }], + ], // Framework you want to run your specs with. // The following are supported: Mocha, Jasmine, and Cucumber