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 } func testLoggedOutProfileShowsLoginPrompt() throws { let app = XCUIApplication() app.launch() XCTAssertTrue(app.reachLoggedOutProfile(), "Never reached the logged-out profile screen") XCTAssertTrue(app.staticTexts["Entre na sua conta"].exists) XCTAssertTrue(app.staticTexts["Faça login ou cadastre-se para ver seu perfil, pedidos e endereços."].exists) XCTAssertTrue(app.buttons["Entrar ou Cadastrar"].isHittable) } /// The auth intro screen must offer both entry points plus the legal /// links, and — the reason App Review rejected the build in 2026-08 — /// a working way back out (its `LCENavigationView` back button, which /// sets `root = .main`). func testAuthIntroScreenShowsChoicesAndCanGoBack() throws { let app = XCUIApplication() app.launch() XCTAssertTrue(app.reachLoggedOutProfile()) app.buttons["Entrar ou Cadastrar"].tap() XCTAssertTrue(app.buttons["Criar conta"].waitForExistence(timeout: 5), "Auth intro missing 'Criar conta'") XCTAssertTrue(app.buttons["Entrar"].exists, "Auth intro missing 'Entrar'") XCTAssertTrue(app.buttons["Termos de Uso"].exists, "Auth intro missing 'Termos de Uso' link") XCTAssertTrue(app.buttons["Política de Privacidade"].exists, "Auth intro missing 'Política de Privacidade' link") let backButton = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch XCTAssertTrue(backButton.exists, "Auth intro has no back button — user is trapped") backButton.tap() // Back out of `.auth` lands on the main tab bar again. XCTAssertTrue(app.buttons["Home"].waitForExistence(timeout: 5), "Back button did not return to the main flow") } /// The pushed auth screens (Registration, LoginEmail) must carry the /// app's standard `AppBackButtonIcon` via `LCENavigationView`, not the /// oversized iOS 26 system glass back button. func testPushedAuthScreensUseAppBackButton() throws { let app = XCUIApplication() app.launch() XCTAssertTrue(app.reachLoggedOutProfile()) app.buttons["Entrar ou Cadastrar"].tap() XCTAssertTrue(app.buttons["Criar conta"].waitForExistence(timeout: 5)) app.buttons["Criar conta"].tap() XCTAssertTrue(app.staticTexts["Crie sua conta"].waitForExistence(timeout: 5)) let regBack = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch XCTAssertTrue(regBack.exists, "Registration screen has no LCENavigationView back button") regBack.tap() XCTAssertTrue(app.buttons["Entrar"].waitForExistence(timeout: 5)) app.buttons["Entrar"].tap() XCTAssertTrue(app.staticTexts["Boas-vindas!"].waitForExistence(timeout: 5)) let loginBack = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch XCTAssertTrue(loginBack.exists, "Login e-mail screen has no LCENavigationView back button") loginBack.tap() XCTAssertTrue(app.buttons["Criar conta"].waitForExistence(timeout: 5), "Back did not return to the auth intro") } }