From 57018f223093276ba2e6e219f8401de7342afd45 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Wed, 9 Sep 2026 15:28:53 -0400 Subject: [PATCH] fix(tests): cancel a cash link through the details screen `testCashLink_createAndCancel` has failed on `main` since #733, which made an activity row open its Details screen instead of prompting to cancel. The test still tapped the "Sending" row and waited for the "Cancel Transfer" button, which never appears without a trip through the screen's trailing Cancel action. The test now waits for the Details screen after the tap, taps that Cancel action, and confirms the dialog. The details steps live in a `TransactionDetailsUIScreen` page object alongside the other screens. No app code changes. --- .../Regression/CashLinkRegressionTests.swift | 20 +++---- .../Screens/TransactionDetailsUIScreen.swift | 60 +++++++++++++++++++ 2 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 FlipcashUITests/Support/Screens/TransactionDetailsUIScreen.swift diff --git a/FlipcashUITests/Regression/CashLinkRegressionTests.swift b/FlipcashUITests/Regression/CashLinkRegressionTests.swift index aae11fcb5..333f3b243 100644 --- a/FlipcashUITests/Regression/CashLinkRegressionTests.swift +++ b/FlipcashUITests/Regression/CashLinkRegressionTests.swift @@ -6,7 +6,7 @@ import XCTest /// Regression test for the cash link lifecycle: create a cash link, confirm it was "sent", -/// then navigate to transaction history and cancel it. +/// then navigate to transaction history and cancel it from the row's details. /// /// **Prerequisites:** /// - A valid `FLIPCASH_UI_TEST_ACCESS_KEY` set in `secrets.local.xcconfig` @@ -22,6 +22,7 @@ final class CashLinkRegressionTests: BaseUITestCase { func testCashLink_createAndCancel() { let currencyInfo = CurrencyInfoUIScreen(app: app) + let details = TransactionDetailsUIScreen(app: app) assertMainScreenReached() @@ -60,22 +61,19 @@ final class CashLinkRegressionTests: BaseUITestCase { // per-token history. currencyInfo.tapRecentActivityHeader(from: self) - // Step 3: Tap the first "Sending" row to trigger the cancel dialog. - // Rows are List cells containing "Sending" as a static text label. - // There may be multiple pending cash links — tap the most recent (first) one. + // Step 3: Open the first "Sending" row. Rows are List cells containing + // "Sending" as a static text label. There may be multiple pending cash + // links — open the most recent (first) one. Tapping a row pushes the + // transaction's Details screen; it no longer prompts to cancel directly. let sendingLabel = app.staticTexts.matching(identifier: "Sending").firstMatch XCTAssertTrue( sendingLabel.waitForExistence(timeout: 10), "Expected a 'Sending' transaction in history" ) sendingLabel.tap() + details.assertReached() - // Step 4: Confirm cancellation. - let cancelTransfer = app.buttons["Cancel Transfer"] - XCTAssertTrue( - cancelTransfer.waitForExistence(timeout: 5), - "Expected 'Cancel Transfer' confirmation dialog" - ) - cancelTransfer.tap() + // Step 4: Cancel from the Details screen's trailing action and confirm. + details.cancelTransfer(from: self) } } diff --git a/FlipcashUITests/Support/Screens/TransactionDetailsUIScreen.swift b/FlipcashUITests/Support/Screens/TransactionDetailsUIScreen.swift new file mode 100644 index 000000000..f8195458c --- /dev/null +++ b/FlipcashUITests/Support/Screens/TransactionDetailsUIScreen.swift @@ -0,0 +1,60 @@ +// +// TransactionDetailsUIScreen.swift +// FlipcashUITests +// + +import XCTest + +/// Page object for `TransactionDetailsScreen` — the screen a tapped activity +/// row pushes from the per-token history. +/// +/// Cancelling a pending cash link is the bar's trailing "Cancel" action, which +/// confirms through a "Cancel … Transfer?" dialog rather than acting directly. +@MainActor +struct TransactionDetailsUIScreen { + + private let app: XCUIApplication + + init(app: XCUIApplication) { + self.app = app + } + + // MARK: - Elements + + /// The screen's inline navigation title. + var navigationBar: XCUIElement { app.navigationBars["Details"] } + + /// The bar's trailing Cancel action, present only while the activity can + /// still be cancelled. + var cancelButton: XCUIElement { navigationBar.buttons["Cancel"] } + + /// The destructive confirmation in the "Cancel … Transfer?" dialog. + var cancelTransferButton: XCUIElement { app.buttons["Cancel Transfer"] } + + // MARK: - Actions + + /// Cancels the shown transfer: taps the bar's Cancel action, then confirms + /// the dialog. + func cancelTransfer(from testCase: BaseUITestCase) { + testCase.waitAndTap( + cancelButton, + timeout: 10, + "Expected the Details screen's Cancel action for a pending cash link" + ) + testCase.waitAndTap( + cancelTransferButton, + timeout: 5, + "Expected 'Cancel Transfer' confirmation dialog" + ) + } + + // MARK: - Assertions + + /// Asserts the details screen was pushed. + func assertReached(timeout: TimeInterval = 10) { + XCTAssertTrue( + navigationBar.waitForExistence(timeout: timeout), + "Expected the transaction Details screen (navigation title 'Details')" + ) + } +}