diff --git a/PediFoodsUITests/HomeGuestFlowTests.swift b/PediFoodsUITests/HomeGuestFlowTests.swift index 34a61be..fd8b24d 100644 --- a/PediFoodsUITests/HomeGuestFlowTests.swift +++ b/PediFoodsUITests/HomeGuestFlowTests.swift @@ -6,23 +6,31 @@ import XCTest /// blocked by a separate login-navigation issue documented there and are /// not covered here. final class HomeGuestFlowTests: XCTestCase { + /// Authenticated-flow tests no longer log out after themselves (see + /// decisions/2026-09-11-ui-test-shared-login-session.md), so this + /// class must force a clean logged-out state before its tests run, + /// rather than assume one. Done once per class, not once per test: + /// the underlying navigate-to-Profile-tab dance + /// (`reachProfileTabRegardlessOfAuthState`) is a known race against + /// the guest address-picker sheet (see + /// decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md) - + /// running it a second time back-to-back inside every test (once + /// here, once again inside `reachGuestHome`'s own callers) doubled + /// exposure to that race and broke tests that were previously stable. + override class func setUp() { + super.setUp() + let app = XCUIApplication() + app.launch() + app.logoutIfAuthenticated() + } + override func setUpWithError() throws { continueAfterFailure = false } - /// Authenticated-flow tests no longer log out after themselves (see - /// decisions/2026-09-11-ui-test-shared-login-session.md), so guest - /// tests must force a clean logged-out state themselves right after - /// launch, rather than assume one. - private func launchGuestApp() -> XCUIApplication { + func testHomeRendersSearchAndGreeting() throws { let app = XCUIApplication() app.launch() - app.logoutIfAuthenticated() - return app - } - - func testHomeRendersSearchAndGreeting() throws { - let app = launchGuestApp() XCTAssertTrue(app.reachGuestHome(), "Never reached Home's search field") XCTAssertTrue(app.staticTexts["ENTREGAR EM:"].exists) @@ -31,7 +39,8 @@ final class HomeGuestFlowTests: XCTestCase { } func testHomeShowsDefaultCategoryChip() throws { - let app = launchGuestApp() + let app = XCUIApplication() + app.launch() XCTAssertTrue(app.reachGuestHome()) XCTAssertTrue(app.staticTexts["Categories"].exists) @@ -39,7 +48,8 @@ final class HomeGuestFlowTests: XCTestCase { } func testHomeShowsGuestLocationPromptWhenNoLocationChosen() throws { - let app = launchGuestApp() + let app = XCUIApplication() + app.launch() XCTAssertTrue(app.reachGuestHome()) // No guest state/city selected -> Home's own inline message, not @@ -48,7 +58,8 @@ final class HomeGuestFlowTests: XCTestCase { } func testTappingAddressChipReopensLocationPicker() throws { - let app = launchGuestApp() + let app = XCUIApplication() + app.launch() XCTAssertTrue(app.reachGuestHome()) // The "ENTREGAR EM:" address button re-opens the same address diff --git a/PediFoodsUITests/OrderDetailsFlowTests.swift b/PediFoodsUITests/OrderDetailsFlowTests.swift index 5a3a987..b1c3b82 100644 --- a/PediFoodsUITests/OrderDetailsFlowTests.swift +++ b/PediFoodsUITests/OrderDetailsFlowTests.swift @@ -21,8 +21,14 @@ final class OrderDetailsFlowTests: XCTestCase { XCTAssertTrue(app.staticTexts["Meus Pedidos"].waitForExistence(timeout: 10)) // "Ver Detalhes" appears once per order card; this account has real - // order history (confirmed in AuthenticatedProfileNavigationTests). - let detailsButton = app.buttons["Ver Detalhes"] + // order history (confirmed in AuthenticatedProfileNavigationTests) + // which has grown to more than one order across many manual and + // automated runs, so an exact-match subscript now resolves to + // multiple elements and throws on .tap() ("Find single matching + // element"). .firstMatch tolerates any count - the test only + // needs *an* order's details screen to be reachable, not a + // specific one. + let detailsButton = app.buttons.matching(NSPredicate(format: "label == %@", "Ver Detalhes")).firstMatch XCTAssertTrue(detailsButton.waitForExistence(timeout: 10), "No orders with a 'Ver Detalhes' action found") detailsButton.tap() diff --git a/PediFoodsUITests/ProfileLoggedOutFlowTests.swift b/PediFoodsUITests/ProfileLoggedOutFlowTests.swift index 068bfa6..d49eb03 100644 --- a/PediFoodsUITests/ProfileLoggedOutFlowTests.swift +++ b/PediFoodsUITests/ProfileLoggedOutFlowTests.swift @@ -3,23 +3,32 @@ import XCTest /// Covers the Profile tab's logged-out state (`ProfileLoggedOutView`) and /// the auth intro screen (`LoginView`) it opens. final class ProfileLoggedOutFlowTests: XCTestCase { + /// Authenticated-flow tests no longer log out after themselves (see + /// decisions/2026-09-11-ui-test-shared-login-session.md), so this + /// class must force a clean logged-out state before its tests run, + /// rather than assume one. Done once per class, not once per test: + /// the underlying navigate-to-Profile-tab dance + /// (`reachProfileTabRegardlessOfAuthState`) is a known race against + /// the guest address-picker sheet (see + /// decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md) - + /// running it a second time back-to-back inside every test (once + /// here, once again inside `reachLoggedOutProfile`'s own callers) + /// doubled exposure to that race and broke tests that were + /// previously stable. + override class func setUp() { + super.setUp() + let app = XCUIApplication() + app.launch() + app.logoutIfAuthenticated() + } + override func setUpWithError() throws { continueAfterFailure = false } - /// Authenticated-flow tests no longer log out after themselves (see - /// decisions/2026-09-11-ui-test-shared-login-session.md), so - /// logged-out tests must force a clean state themselves right after - /// launch, rather than assume one. - private func launchLoggedOutApp() -> XCUIApplication { + func testLoggedOutProfileShowsLoginPrompt() throws { let app = XCUIApplication() app.launch() - app.logoutIfAuthenticated() - return app - } - - func testLoggedOutProfileShowsLoginPrompt() throws { - let app = launchLoggedOutApp() XCTAssertTrue(app.reachLoggedOutProfile(), "Never reached the logged-out profile screen") XCTAssertTrue(app.staticTexts["Entre na sua conta"].exists) @@ -32,7 +41,8 @@ final class ProfileLoggedOutFlowTests: XCTestCase { /// a working way back out (its `LCENavigationView` back button, which /// sets `root = .main`). func testAuthIntroScreenShowsChoicesAndCanGoBack() throws { - let app = launchLoggedOutApp() + let app = XCUIApplication() + app.launch() XCTAssertTrue(app.reachLoggedOutProfile()) app.buttons["Entrar ou Cadastrar"].tap() @@ -54,7 +64,8 @@ final class ProfileLoggedOutFlowTests: XCTestCase { /// app's standard `AppBackButtonIcon` via `LCENavigationView`, not the /// oversized iOS 26 system glass back button. func testPushedAuthScreensUseAppBackButton() throws { - let app = launchLoggedOutApp() + let app = XCUIApplication() + app.launch() XCTAssertTrue(app.reachLoggedOutProfile()) app.buttons["Entrar ou Cadastrar"].tap()