From a5c26bd93949ad8e1f216eaf42b4917aeff4d426 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Wed, 2 Sep 2026 20:01:04 -0400 Subject: [PATCH 1/2] fix(tests): answer the rename confirmation in the display name smoke test Renaming from My Account raises "Change Display Name?" on Save, so `ProfileNameScreen` stayed up behind the dialog and the test burned its 60s wait for the pop back to My Account. Tap the dialog's confirm action between Save and that assertion; landing back on My Account still proves the name was accepted. --- FlipcashUITests/Smoke/DisplayNameSmokeTests.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift b/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift index ac59c7bf3..da4ad1ada 100644 --- a/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift +++ b/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift @@ -75,6 +75,19 @@ final class DisplayNameSmokeTests: BaseUITestCase { XCTAssertTrue(save.isEnabled, "Save must enable once the name is valid and changed") save.tap() + // Replacing a name that is already set is confirmed first; only the + // first name set during onboarding saves straight through. The editor + // stays up behind the dialog until it is answered. + let confirmDialog = app.otherElements["Change Display Name?"] + XCTAssertTrue( + confirmDialog.waitForExistence(timeout: 30), + "Expected the rename confirmation dialog. On screen: [\(visibleText())]" + ) + waitUntilHittableAndTap( + confirmDialog.buttons["Change Display Name"], + "Expected the dialog's Change Display Name action to be tappable" + ) + // `ProfileNameScreen(completion: .back)` pops itself only once // `SetDisplayName` returns, so landing back on My Account is proof the // new name was accepted and moderated — a rejection keeps the editor up From cccff4d6a95fa95fd760988dc895741a352d6d06 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Wed, 2 Sep 2026 21:47:34 -0400 Subject: [PATCH 2/2] fix(tests): wait for Save to disable on an empty name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `save.isEnabled` was read straight after the deletes, which catches the state the button is leaving: the emptied field reaches it on SwiftUI's next render, and under a full-suite load that lands after the typing has settled. Failed once that way in a full run — the field read back as its placeholder, so it was already empty. Wait for `isEnabled == false` instead, the way the phone-verification helper waits for its Confirm button, and name the field's contents when the wait times out. --- FlipcashUITests/Smoke/DisplayNameSmokeTests.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift b/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift index da4ad1ada..9b17c9816 100644 --- a/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift +++ b/FlipcashUITests/Smoke/DisplayNameSmokeTests.swift @@ -69,7 +69,19 @@ final class DisplayNameSmokeTests: BaseUITestCase { let seeded = (field.value as? String) ?? "" XCTAssertFalse(seeded.isEmpty, "Expected the editor to be seeded with the current name") field.typeText(String(repeating: XCUIKeyboardKey.delete.rawValue, count: seeded.count)) - XCTAssertFalse(save.isEnabled, "Save must stay disabled while the name is empty") + + // Wait for the disabled state rather than sampling it: the emptied field + // reaches the button on SwiftUI's next render, which under load lands + // after the typing settles. The field is already empty by then — the + // instantaneous read just catches the state the button is leaving. + let saveDisabled = XCTNSPredicateExpectation( + predicate: NSPredicate(format: "isEnabled == false"), + object: save + ) + XCTAssertEqual( + XCTWaiter().wait(for: [saveDisabled], timeout: 5), .completed, + "Save must stay disabled while the name is empty. Field: [\((field.value as? String) ?? "")]" + ) field.typeText("Renamed \(Int.random(in: 1_000...9_999))") XCTAssertTrue(save.isEnabled, "Save must enable once the name is valid and changed")