Skip to content
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
112 changes: 85 additions & 27 deletions test/helpers/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1184,10 +1184,6 @@ export async function transferSpendingToSavings() {
await elementById('TransferSuccess-button').waitForDisplayed();
await tap('TransferSuccess-button');

if (driver.isAndroid) {
await doNavigationClose();
}

await sleep(1000);
await expectSavingsBalance(0, { condition: 'gt' });
await expectSpendingBalance(0);
Expand Down Expand Up @@ -1396,6 +1392,10 @@ export async function waitForToast(
* or dismissed too quickly). Does not throw on timeout—callers must handle
* verification via other means (e.g., UI state confirmation).
*
* Once the toast is observed it is cleared before returning, so it cannot keep
* covering the header: a toast overlays HeaderMenu for its whole lifetime and
* swallows the tap that opens the drawer.
*
* On iOS, uses waitToDisappear pattern since toasts render in a separate window
* where drag-dismiss hits wrong coordinates.
*/
Expand All @@ -1421,17 +1421,31 @@ export async function waitForToastBestEffort(
},
{ timeout, interval: pollingInterval }
);

if (driver.isIOS) {
await el.waitForDisplayed({ reverse: true, timeout: 5_000 }).catch(() => {
// Toast may have dismissed immediately; that's fine
});
}
} catch {
// Toast wasn't displayed within timeout—may have already appeared and dismissed
// or never appeared. Caller should verify via other means.
}

if (!toastSeen) {
return false;
}

// Re-check instead of trusting toastSeen: dragOnElement waits on the element
// with the global 30s timeout, which would be spent in full on a toast that
// already went away.
if (driver.isAndroid && (await el.isDisplayed().catch(() => false))) {
// Drag it away like waitForToast does: an undismissed toast keeps covering
// HeaderMenu for its full duration, so the next openSettings() tap lands on
// the toast instead of the drawer button.
await dragOnElement(toastId, 'up', 0.2).catch(() => {
// Toast may have auto-dismissed mid-drag; the wait below settles it
});
}

await el.waitForDisplayed({ reverse: true, timeout: 5_000 }).catch(() => {
// Toast may have dismissed immediately; that's fine
});

return toastSeen;
}

Expand Down Expand Up @@ -1471,28 +1485,72 @@ export async function acknowledgeExternalSuccess() {
await sleep(300);
}

/**
* Dismisses the Background Payments timed sheet if it is present.
*
* Best-effort: the intro can already be gone (auto-dismissed, previously
* acknowledged, or never queued after HeaderMenu). Does not throw when the
* dismiss control is missing — callers continue. When the intro IS shown,
* it is still dismissed via Later / Cancel so remaining coverage can run
* on an unobstructed home screen.
*
* Pattern matches waitForToastBestEffort: poll for visibility, act if seen,
* swallow timeout if the sheet never appeared or vanished mid-dismiss.
*
* @returns true if the sheet was observed and a dismiss was attempted,
* false if it was already gone.
*/
export async function dismissBackgroundPaymentsTimedSheet({
triggerTimedSheet = false,
}: { triggerTimedSheet?: boolean } = {}) {
if (triggerTimedSheet) {
await doTriggerTimedSheet();
timeout = 10_000,
}: { triggerTimedSheet?: boolean; timeout?: number } = {}): Promise<boolean> {
const sheetId = driver.isAndroid
? 'BackgroundPaymentsIntro-later'
: 'BackgroundPaymentsDescription';
const dismissId = driver.isAndroid ? 'BackgroundPaymentsIntro-later' : 'BackgroundPaymentsCancel';

await triggerTimedSheetUnlessPresent(sheetId, triggerTimedSheet);

const el = elementById(sheetId);
let sheetSeen = false;

try {
await browser.waitUntil(
async () => {
const displayed = await el.isDisplayed().catch(() => false);
if (displayed) {
sheetSeen = true;
return true;
}
return false;
},
{ timeout, interval: 200 }
);
} catch {
// Sheet wasn't displayed within timeout — may have already appeared and
// dismissed, or never appeared after the HeaderMenu trigger race.
console.info(`→ ${sheetId} not displayed; treating Background Payments intro as already gone`);
return false;
}

if (driver.isAndroid) {
await elementById('BackgroundPaymentsIntro-later').waitForDisplayed();
await sleep(500); // wait for the app to settle
await tap('BackgroundPaymentsIntro-later');
} else {
const description = elementById('BackgroundPaymentsDescription');
await description.waitForDisplayed();
const cancel = elementById('BackgroundPaymentsCancel');
await cancel.waitForDisplayed();
// The iOS sheet animates while appearing. Click a fresh element reference
// immediately; the generic tap() delay makes this button prone to staleness.
await cancel.click();
await description.waitForDisplayed({ reverse: true });
if (!sheetSeen) {
return false;
}
await sleep(500);

await sleep(500); // wait for the app to settle
try {
const dismissEl = elementById(dismissId);
const stillShown = await dismissEl.isDisplayed().catch(() => false);
if (!stillShown) {
console.info(`→ ${dismissId} gone before dismiss tap; treating intro as already dismissed`);
return true;
}
await dismissEl.click();
await sleep(500);
} catch (error) {
console.info(`→ ${dismissId} disappeared before dismiss tap; continuing`, error);
}
return true;
}

async function isTestIdDisplayed(testId: string): Promise<boolean> {
Expand Down
1 change: 0 additions & 1 deletion test/specs/transfer.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@ describe('@transfer - Transfer', () => {
await dragOnElement('GRAB', 'right', 0.95);
await elementById('TransferSuccess').waitForDisplayed();
await tap('TransferSuccess-button');
if (driver.isAndroid) await tap('NavigationBack');
await sleep(1000);

// check channel is closed
Expand Down