From 32faa5a6668f431fd0d186ac00743a94826a271e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 28 Sep 2026 17:19:11 +0200 Subject: [PATCH 1/3] test: keep paykit ui helpers idempotent --- test/helpers/paykit.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/helpers/paykit.ts b/test/helpers/paykit.ts index 23c1e3a9..3c0fd808 100644 --- a/test/helpers/paykit.ts +++ b/test/helpers/paykit.ts @@ -18,6 +18,15 @@ async function scrollToPaykitToggle() { await elementById(PAYKIT_UI_TOGGLE_ID).waitForDisplayed(); } +async function isPaykitUiToggleOn() { + await scrollToPaykitToggle(); + const toggle = elementById(PAYKIT_UI_TOGGLE_ID); + const state = driver.isIOS + ? await toggle.getAttribute('value') + : await toggle.getAttribute('checked'); + return state === '1' || state === 'true'; +} + async function tapPaykitUiToggle() { await scrollToPaykitToggle(); await tap(PAYKIT_UI_TOGGLE_ID); @@ -36,9 +45,14 @@ async function leaveDevSettings() { await doNavigationClose(); } +// Paykit UI is on by default; the helpers only tap the Dev Settings switch when it is in the other state. export async function enablePaykitUi() { await elementById('TotalBalance-primary').waitForDisplayed({ timeout: 60_000 }); await openDevSettings(); + if (await isPaykitUiToggleOn()) { + await leaveDevSettings(); + return; + } await tapPaykitUiToggle(); await confirmPaykitUiEnableDialogIfPresent(); try { @@ -51,6 +65,10 @@ export async function enablePaykitUi() { export async function disablePaykitUi() { await openDevSettings(); + if (!(await isPaykitUiToggleOn())) { + await leaveDevSettings(); + return; + } await tapPaykitUiToggle(); await waitForToast('PaykitUiDisabledToast', { waitToDisappear: driver.isIOS }); await leaveDevSettings(); From e67d40ba1dd0f85a9594a57b72390878d82fe1f8 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 28 Sep 2026 18:06:21 +0200 Subject: [PATCH 2/3] test: drop paykit dev settings helpers --- test/helpers/actions.ts | 2 - test/helpers/navigation.ts | 10 ---- test/helpers/paykit.ts | 83 --------------------------------- test/helpers/qa-fixture.ts | 2 - test/specs/paykit.e2e.ts | 2 - test/specs/pubky-profile.e2e.ts | 30 ++++++------ 6 files changed, 15 insertions(+), 114 deletions(-) delete mode 100644 test/helpers/paykit.ts diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts index 1670e127..98e6e567 100644 --- a/test/helpers/actions.ts +++ b/test/helpers/actions.ts @@ -1388,8 +1388,6 @@ export type ToastId = | 'ExpiredLightningToast' | 'DevModeEnabledToast' | 'DevModeDisabledToast' - | 'PaykitUiEnabledToast' - | 'PaykitUiDisabledToast' | 'InsufficientSpendingToast' | 'InsufficientSavingsToast' | 'ProfilePubkyCopiedToast' diff --git a/test/helpers/navigation.ts b/test/helpers/navigation.ts index 332a0b49..f361655e 100644 --- a/test/helpers/navigation.ts +++ b/test/helpers/navigation.ts @@ -28,16 +28,6 @@ export async function openSupport() { await sleep(500); } -/** - * Opens Dev Settings from the Advanced settings tab. - */ -export async function openDevSettings() { - await openSettings('advanced'); - await elementById('DevSettings').waitForDisplayed(); - await tap('DevSettings'); - await sleep(500); -} - /** * Opens the Contacts entry from the drawer menu. */ diff --git a/test/helpers/paykit.ts b/test/helpers/paykit.ts deleted file mode 100644 index 3c0fd808..00000000 --- a/test/helpers/paykit.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { elementById, elementByText, sleep, swipeFullScreen, tap, waitForToast } from './actions'; -import { doNavigationClose, openDevSettings } from './navigation'; - -const PAYKIT_UI_TOGGLE_ID = 'PaykitUiToggle'; - -async function scrollToPaykitToggle() { - for (let attempt = 0; attempt < 4; attempt++) { - if ( - await elementById(PAYKIT_UI_TOGGLE_ID) - .isDisplayed() - .catch(() => false) - ) { - return; - } - await swipeFullScreen('up'); - await sleep(300); - } - await elementById(PAYKIT_UI_TOGGLE_ID).waitForDisplayed(); -} - -async function isPaykitUiToggleOn() { - await scrollToPaykitToggle(); - const toggle = elementById(PAYKIT_UI_TOGGLE_ID); - const state = driver.isIOS - ? await toggle.getAttribute('value') - : await toggle.getAttribute('checked'); - return state === '1' || state === 'true'; -} - -async function tapPaykitUiToggle() { - await scrollToPaykitToggle(); - await tap(PAYKIT_UI_TOGGLE_ID); -} - -async function confirmPaykitUiEnableDialogIfPresent() { - const enableButton = elementByText('Enable', 'exact'); - if (await enableButton.isDisplayed().catch(() => false)) { - await enableButton.click(); - await sleep(500); - } -} - -async function leaveDevSettings() { - await tap('NavigationBack'); - await doNavigationClose(); -} - -// Paykit UI is on by default; the helpers only tap the Dev Settings switch when it is in the other state. -export async function enablePaykitUi() { - await elementById('TotalBalance-primary').waitForDisplayed({ timeout: 60_000 }); - await openDevSettings(); - if (await isPaykitUiToggleOn()) { - await leaveDevSettings(); - return; - } - await tapPaykitUiToggle(); - await confirmPaykitUiEnableDialogIfPresent(); - try { - await waitForToast('PaykitUiEnabledToast', { waitToDisappear: driver.isIOS, timeout: 15_000 }); - } catch (error) { - console.info('→ PaykitUiEnabledToast not shown (already hidden or skipped)', error); - } - await leaveDevSettings(); -} - -export async function disablePaykitUi() { - await openDevSettings(); - if (!(await isPaykitUiToggleOn())) { - await leaveDevSettings(); - return; - } - await tapPaykitUiToggle(); - await waitForToast('PaykitUiDisabledToast', { waitToDisappear: driver.isIOS }); - await leaveDevSettings(); -} - -export async function setPaykitUiEnabled(enabled: boolean) { - if (enabled) { - await enablePaykitUi(); - } else { - await disablePaykitUi(); - } -} diff --git a/test/helpers/qa-fixture.ts b/test/helpers/qa-fixture.ts index bc12013f..ecfacdea 100644 --- a/test/helpers/qa-fixture.ts +++ b/test/helpers/qa-fixture.ts @@ -3,7 +3,6 @@ import path from 'node:path'; import { completeOnboarding, receiveOnchainFunds, transferSavingsToSpending } from './actions'; import { doNavigationClose } from './navigation'; -import { enablePaykitUi } from './paykit'; import { createProfile } from './profile'; import type { ElectrumClient } from './electrum'; @@ -89,7 +88,6 @@ export async function applyQaFixture( } if (needsProfile(kind)) { - await enablePaykitUi(); result.profileName = profileName(); const created = await createProfile({ name: result.profileName }); result.pubky = created.pubky; diff --git a/test/specs/paykit.e2e.ts b/test/specs/paykit.e2e.ts index bb1e382a..a1b2f7d2 100644 --- a/test/specs/paykit.e2e.ts +++ b/test/specs/paykit.e2e.ts @@ -12,7 +12,6 @@ import { } from '../helpers/actions'; import { STAGING_PAYKIT_CONTACTS } from '../helpers/fixtures'; import { doNavigationClose, openContacts } from '../helpers/navigation'; -import { enablePaykitUi } from '../helpers/paykit'; import { addContact, createProfile, verifyAddContactRoute } from '../helpers/profile'; import { reinstallApp } from '../helpers/setup'; import { ciIt } from '../helpers/suite'; @@ -139,7 +138,6 @@ describe('@pubky @paykit @pubky_staging, @staging - Public payments', () => { beforeEach(async () => { await reinstallApp(); await completeOnboarding(); - await enablePaykitUi(); }); ciIt('@paykit_1 - Can pay saved contact via public on-chain endpoint', async () => { diff --git a/test/specs/pubky-profile.e2e.ts b/test/specs/pubky-profile.e2e.ts index 3cf6ddb2..d481ae7f 100644 --- a/test/specs/pubky-profile.e2e.ts +++ b/test/specs/pubky-profile.e2e.ts @@ -15,7 +15,6 @@ import { } from '../helpers/actions'; import { STAGING_TEST_CONTACTS } from '../helpers/fixtures'; import { openContacts, openProfile } from '../helpers/navigation'; -import { enablePaykitUi } from '../helpers/paykit'; import { addContact, ADD_CONTACT_INVALID_KEY_MESSAGE_SNIPPET, @@ -48,7 +47,6 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => beforeEach(async () => { await reinstallApp(); await completeOnboarding(); - await enablePaykitUi(); }); // Section A: with no profile, every entry point must funnel into the choice screen. @@ -125,7 +123,7 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => console.warn(error); } await restoreWallet(seed); - await enablePaykitUi(); + await elementById('TotalBalance-primary').waitForDisplayed({ timeout: 60_000 }); await verifyMyProfileDetails(details); const pubkyAfterRestore = await readPubkyFromProfileCopy(); await expect(pubkyAfterRestore).toBe(pubky.trim()); @@ -235,7 +233,6 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => ); await reinstallApp(); await completeOnboarding(); - await enablePaykitUi(); await createProfile({ name: 'Bob Wallet B' }); await addContact({ pubky: pubkyA, firstContact: true }); @@ -256,7 +253,7 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => 'Wallet A: restore wallet A and verify wallet A profile is unchanged by wallet B contact edits.' ); await restoreWallet(seedA); - await enablePaykitUi(); + await elementById('TotalBalance-primary').waitForDisplayed({ timeout: 60_000 }); await verifyMyProfileDetails(detailsA); } ); @@ -266,17 +263,20 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => // (staging Homegate). Send/manual ignores pubkyauth:// — only the home scanner handles it. // Ring QR (`pubkyring://signup`) and Import-with-Ring stay manual (charter C). describe('Scanner signup (no Ring)', () => { - ciIt('@pubky_profile_5 - After profile, home scanner signup says already signed in', async () => { - const directSignupUrl = - 'pubkyauth://direct_signup?hs=ufibwbmed6jeq9k4p583go95wofakh9fwpp4k734trq79pd9u1uy'; + ciIt( + '@pubky_profile_5 - After profile, home scanner signup says already signed in', + async () => { + const directSignupUrl = + 'pubkyauth://direct_signup?hs=ufibwbmed6jeq9k4p583go95wofakh9fwpp4k734trq79pd9u1uy'; - await createProfile({ name: 'Signup Scanner' }); - await doNavigationClose(); + await createProfile({ name: 'Signup Scanner' }); + await doNavigationClose(); - await enterAddressViaScanPrompt(directSignupUrl, { acceptCameraPermission: true }); - await elementByText('Already signed in', 'exact').waitForDisplayed({ timeout: 15_000 }); - await expect(elementById('CreateProfileUsername')).not.toBeDisplayed(); - await expect(elementById('PubkyAuthAuthorize')).not.toBeDisplayed(); - }); + await enterAddressViaScanPrompt(directSignupUrl, { acceptCameraPermission: true }); + await elementByText('Already signed in', 'exact').waitForDisplayed({ timeout: 15_000 }); + await expect(elementById('CreateProfileUsername')).not.toBeDisplayed(); + await expect(elementById('PubkyAuthAuthorize')).not.toBeDisplayed(); + } + ); }); }); From 9bbfa5190ff5ba17377b3df32ff9171f9eb45b7f Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 28 Sep 2026 18:48:48 +0200 Subject: [PATCH 3/3] test: drop redundant waits after wallet restore --- test/specs/pubky-profile.e2e.ts | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/test/specs/pubky-profile.e2e.ts b/test/specs/pubky-profile.e2e.ts index d481ae7f..1c80b134 100644 --- a/test/specs/pubky-profile.e2e.ts +++ b/test/specs/pubky-profile.e2e.ts @@ -123,7 +123,6 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => console.warn(error); } await restoreWallet(seed); - await elementById('TotalBalance-primary').waitForDisplayed({ timeout: 60_000 }); await verifyMyProfileDetails(details); const pubkyAfterRestore = await readPubkyFromProfileCopy(); await expect(pubkyAfterRestore).toBe(pubky.trim()); @@ -253,7 +252,6 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => 'Wallet A: restore wallet A and verify wallet A profile is unchanged by wallet B contact edits.' ); await restoreWallet(seedA); - await elementById('TotalBalance-primary').waitForDisplayed({ timeout: 60_000 }); await verifyMyProfileDetails(detailsA); } ); @@ -263,20 +261,17 @@ describe('@pubky @pubky_profile @pubky_staging, @staging - Pubky profile', () => // (staging Homegate). Send/manual ignores pubkyauth:// — only the home scanner handles it. // Ring QR (`pubkyring://signup`) and Import-with-Ring stay manual (charter C). describe('Scanner signup (no Ring)', () => { - ciIt( - '@pubky_profile_5 - After profile, home scanner signup says already signed in', - async () => { - const directSignupUrl = - 'pubkyauth://direct_signup?hs=ufibwbmed6jeq9k4p583go95wofakh9fwpp4k734trq79pd9u1uy'; + ciIt('@pubky_profile_5 - After profile, home scanner signup says already signed in', async () => { + const directSignupUrl = + 'pubkyauth://direct_signup?hs=ufibwbmed6jeq9k4p583go95wofakh9fwpp4k734trq79pd9u1uy'; - await createProfile({ name: 'Signup Scanner' }); - await doNavigationClose(); + await createProfile({ name: 'Signup Scanner' }); + await doNavigationClose(); - await enterAddressViaScanPrompt(directSignupUrl, { acceptCameraPermission: true }); - await elementByText('Already signed in', 'exact').waitForDisplayed({ timeout: 15_000 }); - await expect(elementById('CreateProfileUsername')).not.toBeDisplayed(); - await expect(elementById('PubkyAuthAuthorize')).not.toBeDisplayed(); - } - ); + await enterAddressViaScanPrompt(directSignupUrl, { acceptCameraPermission: true }); + await elementByText('Already signed in', 'exact').waitForDisplayed({ timeout: 15_000 }); + await expect(elementById('CreateProfileUsername')).not.toBeDisplayed(); + await expect(elementById('PubkyAuthAuthorize')).not.toBeDisplayed(); + }); }); });