From 186c7be85292b11f84a7fbeb6d57c3a777d6b689 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Mon, 12 Jan 2026 18:39:52 +0100 Subject: [PATCH 1/6] Sending to unified invoice w/ expired invoice on iOS after fix --- test/specs/send.e2e.ts | 56 ++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/test/specs/send.e2e.ts b/test/specs/send.e2e.ts index 4cc3bff..dc131af 100644 --- a/test/specs/send.e2e.ts +++ b/test/specs/send.e2e.ts @@ -325,39 +325,31 @@ describe('@send - Send', () => { // send to unified invoice w/ expired invoice let amtAfterUnified3: string; - if (driver.isAndroid) { - console.info('Sending to unified invoice w/ expired invoice...'); - const unified3 = - 'bitcoin:bcrt1qaytrqsrgg75rtxrtr7ur6k75la8p3v95mey48z?lightning=LNBCRT1PN33T20DQQNP4QTNTQ4D2DHDYQ420HAUQF5TS7X32TNW9WGYEPQZQ6R9G69QPHW4RXPP5QU7UYXJYJA9PJV7H6JPEYEFFNZ98N686JDEAAK8AUD5AGC5X70HQSP54V5LEFATCQDEU8TLKAF6MDK3ZLU6MWUA52J4JEMD5XA85KGKMTTQ9QYYSGQCQPCXQRRSSRZJQWU6G4HMGH26EXXQYPQD8XHVWLARA66PL53V7S9CV2EE808UGDRN4APYQQQQQQQGRCQQQQLGQQQQQQGQ2QX7F74RT5SQE0KEYCU47LYMSVY2LM4QA4KLR65PPSY55M0H4VR8AN7WVM9EFVSPYJ5R8EFGVXTGVATAGFTC372VRJ3HEPSEELFZ7FQFCQ9XDU9X'; - console.info({ unified3 }); - - // const ln = - // 'LNBCRT1PN33T20DQQNP4QTNTQ4D2DHDYQ420HAUQF5TS7X32TNW9WGYEPQZQ6R9G69QPHW4RXPP5QU7UYXJYJA9PJV7H6JPEYEFFNZ98N686JDEAAK8AUD5AGC5X70HQSP54V5LEFATCQDEU8TLKAF6MDK3ZLU6MWUA52J4JEMD5XA85KGKMTTQ9QYYSGQCQPCXQRRSSRZJQWU6G4HMGH26EXXQYPQD8XHVWLARA66PL53V7S9CV2EE808UGDRN4APYQQQQQQQGRCQQQQLGQQQQQQGQ2QX7F74RT5SQE0KEYCU47LYMSVY2LM4QA4KLR65PPSY55M0H4VR8AN7WVM9EFVSPYJ5R8EFGVXTGVATAGFTC372VRJ3HEPSEELFZ7FQFCQ9XDU9X'; - // const dec = await lnd.decodePayReq({ payReq: ln }); - // console.info(JSON.stringify(dec, null, 2)); + console.info('Sending to unified invoice w/ expired invoice...'); + const unified3 = + 'bitcoin:bcrt1qaytrqsrgg75rtxrtr7ur6k75la8p3v95mey48z?lightning=LNBCRT1PN33T20DQQNP4QTNTQ4D2DHDYQ420HAUQF5TS7X32TNW9WGYEPQZQ6R9G69QPHW4RXPP5QU7UYXJYJA9PJV7H6JPEYEFFNZ98N686JDEAAK8AUD5AGC5X70HQSP54V5LEFATCQDEU8TLKAF6MDK3ZLU6MWUA52J4JEMD5XA85KGKMTTQ9QYYSGQCQPCXQRRSSRZJQWU6G4HMGH26EXXQYPQD8XHVWLARA66PL53V7S9CV2EE808UGDRN4APYQQQQQQQGRCQQQQLGQQQQQQGQ2QX7F74RT5SQE0KEYCU47LYMSVY2LM4QA4KLR65PPSY55M0H4VR8AN7WVM9EFVSPYJ5R8EFGVXTGVATAGFTC372VRJ3HEPSEELFZ7FQFCQ9XDU9X'; + console.info({ unified3 }); + + // const ln = + // 'LNBCRT1PN33T20DQQNP4QTNTQ4D2DHDYQ420HAUQF5TS7X32TNW9WGYEPQZQ6R9G69QPHW4RXPP5QU7UYXJYJA9PJV7H6JPEYEFFNZ98N686JDEAAK8AUD5AGC5X70HQSP54V5LEFATCQDEU8TLKAF6MDK3ZLU6MWUA52J4JEMD5XA85KGKMTTQ9QYYSGQCQPCXQRRSSRZJQWU6G4HMGH26EXXQYPQD8XHVWLARA66PL53V7S9CV2EE808UGDRN4APYQQQQQQQGRCQQQQLGQQQQQQGQ2QX7F74RT5SQE0KEYCU47LYMSVY2LM4QA4KLR65PPSY55M0H4VR8AN7WVM9EFVSPYJ5R8EFGVXTGVATAGFTC372VRJ3HEPSEELFZ7FQFCQ9XDU9X'; + // const dec = await lnd.decodePayReq({ payReq: ln }); + // console.info(JSON.stringify(dec, null, 2)); - await sleep(1000); - await enterAddress(unified3, { acceptCameraPermission: false }); - await elementById('AssetButton-savings').waitForDisplayed(); - await tap('N1'); - await multiTap('N0', 4); - await tap('ContinueAmount'); - await reviewAmt.waitForDisplayed(); - await expect(reviewAmt).toHaveText('10 000'); - await dragOnElement('GRAB', 'right', 0.95); - await elementById('SendSuccess').waitForDisplayed(); - await tap('Close'); - await expect(totalBalance).not.toHaveText(amtAfterUnified2); - amtAfterUnified3 = await totalBalance.getText(); - console.info({ amtAfterUnified3 }); - await expectTextWithin('ActivitySpending', '7 000'); - } else { - // https://github.com/synonymdev/bitkit-ios/issues/300 - console.info( - 'Skipping sending to unified invoice w/ expired invoice on iOS due to /bitkit-ios/issues/300' - ); - amtAfterUnified3 = amtAfterUnified2; - } + await sleep(1000); + await enterAddress(unified3, { acceptCameraPermission: false }); + await elementById('AssetButton-savings').waitForDisplayed(); + await tap('N1'); + await multiTap('N0', 4); + await tap('ContinueAmount'); + await reviewAmt.waitForDisplayed(); + await expect(reviewAmt).toHaveText('10 000'); + await dragOnElement('GRAB', 'right', 0.95); + await elementById('SendSuccess').waitForDisplayed(); + await tap('Close'); + await expect(totalBalance).not.toHaveText(amtAfterUnified2); + amtAfterUnified3 = await totalBalance.getText(); + console.info({ amtAfterUnified3 }); + await expectTextWithin('ActivitySpending', '7 000'); // send to unified invoice w/o amount (lightning) console.info('Sending to unified invoice w/o amount (lightning)...'); From 4be7740bc35ee1c90a4736bf00750c58071a3547 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Thu, 15 Jan 2026 22:40:51 +0100 Subject: [PATCH 2/6] timeout for CI vs local --- wdio.conf.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wdio.conf.ts b/wdio.conf.ts index c3e904a..a0c8e4f 100644 --- a/wdio.conf.ts +++ b/wdio.conf.ts @@ -123,7 +123,7 @@ export const config: WebdriverIO.Config = { // baseUrl: 'http://localhost:8080', // // Default timeout for all waitFor* commands. - waitforTimeout: 30000, + waitforTimeout: process.env.CI ? 30000 : 10000, // // Default timeout in milliseconds for request // if browser driver or grid doesn't send response From fd60bca4dc7272a0f8582c40830127183a1ef2f8 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Mon, 19 Jan 2026 13:15:09 +0100 Subject: [PATCH 3/6] bigger timeout on init electrum --- test/helpers/electrum.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helpers/electrum.ts b/test/helpers/electrum.ts index 44ce45b..e0618a1 100644 --- a/test/helpers/electrum.ts +++ b/test/helpers/electrum.ts @@ -12,7 +12,7 @@ const peer = { ssl: 60002, }; -const TIMEOUT = 30 * 1000; // 30 seconds +const TIMEOUT = 120 * 1000; // 120 seconds function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -77,7 +77,7 @@ const initElectrum = async (): Promise => { } if (Date.now() - startTime > TIMEOUT) { - throw new Error('Electrum sync timeout'); + throw new Error('Electrum sync timeout exceeded 120 seconds'); } await sleep(1000); From ee5a018ccb10791214fccc816a74620bb2f05146 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Tue, 20 Jan 2026 12:43:17 +0100 Subject: [PATCH 4/6] add electrum stop in numberpad --- test/specs/numberpad.e2e.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/specs/numberpad.e2e.ts b/test/specs/numberpad.e2e.ts index 519d1f6..f96fc03 100644 --- a/test/specs/numberpad.e2e.ts +++ b/test/specs/numberpad.e2e.ts @@ -35,6 +35,10 @@ describe('@numberpad - NumberPad', () => { await receiveOnchainFunds({ sats: 10_000 }); }); + after(async () => { + await electrum?.stop(); + }); + beforeEach(async () => { await launchFreshApp(); await electrum?.waitForSync(); From be54a04a8fe8278e4ec270b505bd4646e55cc678 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Tue, 20 Jan 2026 13:08:09 +0100 Subject: [PATCH 5/6] adjust numberpad --- test/helpers/electrum.ts | 13 +++++++++++++ test/specs/numberpad.e2e.ts | 14 +++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/test/helpers/electrum.ts b/test/helpers/electrum.ts index e0618a1..3fe0394 100644 --- a/test/helpers/electrum.ts +++ b/test/helpers/electrum.ts @@ -76,6 +76,19 @@ const initElectrum = async (): Promise => { break; } + // Actively check if Electrum has the block at nodeHeight + // This handles the case where Electrum is catching up but no new blocks are mined + const { error } = await electrum.getHeader({ + height: nodeHeight, + network: 'bitcoinRegtest', + timeout: 5000, + }); + if (!error) { + // Electrum has caught up to nodeHeight + electrumHeight = nodeHeight; + break; + } + if (Date.now() - startTime > TIMEOUT) { throw new Error('Electrum sync timeout exceeded 120 seconds'); } diff --git a/test/specs/numberpad.e2e.ts b/test/specs/numberpad.e2e.ts index f96fc03..5e3094d 100644 --- a/test/specs/numberpad.e2e.ts +++ b/test/specs/numberpad.e2e.ts @@ -1,4 +1,3 @@ -import BitcoinJsonRpc from 'bitcoin-json-rpc'; import { completeOnboarding, enterAddress, @@ -15,20 +14,13 @@ import { import initElectrum from '../helpers/electrum'; import { launchFreshApp, reinstallApp } from '../helpers/setup'; import { ciIt } from '../helpers/suite'; -import { bitcoinURL } from '../helpers/constants'; +import { ensureLocalFunds } from '../helpers/regtest'; describe('@numberpad - NumberPad', () => { let electrum: Awaited> | undefined; - const rpc = new BitcoinJsonRpc(bitcoinURL); - before(async () => { - let balance = await rpc.getBalance(); - const address = await rpc.getNewAddress(); - - while (balance < 10) { - await rpc.generateToAddress(10, address); - balance = await rpc.getBalance(); - } + before(async () => { + await ensureLocalFunds(); electrum = await initElectrum(); await reinstallApp(); await completeOnboarding(); From 1facde97fcf6cc5548d05dd3c5a4f0122db9c868 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Tue, 20 Jan 2026 13:31:55 +0100 Subject: [PATCH 6/6] adjust security --- test/specs/security.e2e.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/specs/security.e2e.ts b/test/specs/security.e2e.ts index e67e0d5..73f1876 100644 --- a/test/specs/security.e2e.ts +++ b/test/specs/security.e2e.ts @@ -51,6 +51,7 @@ describe('@security - Security And Privacy', () => { await tap('DrawerSettings'); await tap('SecuritySettings'); await tap('PINCode'); + await sleep(1000); await tap('SecureWalletContinue'); await multiTap('N1', PIN_LENGTH); // enter PIN await multiTap('N2', PIN_LENGTH); // retype wrong PIN @@ -63,7 +64,7 @@ describe('@security - Security And Privacy', () => { await doNavigationClose(); // - login with PIN - await launchFreshApp({ tryHandleAlert: false }); + await launchFreshApp(); await elementById('PinPad').waitForDisplayed(); await sleep(1000); await multiTap('N1', PIN_LENGTH); @@ -104,7 +105,7 @@ describe('@security - Security And Privacy', () => { await multiTap('N2', PIN_LENGTH); // correct new pin in the confirmation await tap('OK'); - await launchFreshApp({ tryHandleAlert: false }); + await launchFreshApp(); await elementById('PinPad').waitForDisplayed(); await sleep(1000); await multiTap('N2', PIN_LENGTH); @@ -118,7 +119,7 @@ describe('@security - Security And Privacy', () => { await tap('DisablePin'); await multiTap('N2', PIN_LENGTH); await sleep(1000); - await launchFreshApp({ tryHandleAlert: false }); + await launchFreshApp(); await elementById('TotalBalance').waitForDisplayed(); // enable PIN for last test @@ -126,6 +127,7 @@ describe('@security - Security And Privacy', () => { await tap('DrawerSettings'); await tap('SecuritySettings'); await tap('PINCode'); + await sleep(1000); await tap('SecureWalletContinue'); await multiTap('N1', PIN_LENGTH); // enter PIN await multiTap('N1', PIN_LENGTH); // retype PIN @@ -135,7 +137,7 @@ describe('@security - Security And Privacy', () => { await sleep(1000); // now lets restart the app and fail to enter correct PIN 8 times - await launchFreshApp({ tryHandleAlert: false }); + await launchFreshApp(); await elementById('PinPad').waitForDisplayed(); for (let i = 1; i <= MAX_ATTEMPTS_BEFORE_LAST; i++) { await multiTap('N9', PIN_LENGTH); // wrong PIN