fix(uitests): move forced logout to class setUp, fix ambiguous Ver Detalhes match

Previous commit's per-test logoutIfAuthenticated() in HomeGuestFlowTests
and ProfileLoggedOutFlowTests ran the guest address-picker navigation
dance (reachProfileTabRegardlessOfAuthState) twice back-to-back per test
- once in the new launch helper, once again inside reachGuestHome/
reachLoggedOutProfile - doubling exposure to that dance's known race
and regressing 5 previously-stable tests ('Login never completed' was
fixed, but new failures appeared in its place).

Moved the forced logout into override class func setUp() so it runs
once per class instead of once per test; test bodies are back to the
plain XCUIApplication()+launch() pattern.

Also fixed OrderDetailsFlowTests: 'Ver Detalhes' now matches multiple
elements once the QA account has more than one real order (previously
masked because login itself was failing first). Switched to a label
predicate + .firstMatch.

See decisions/2026-09-11-ui-test-shared-login-session.md follow-ups.
This commit is contained in:
2026-09-11 10:00:51 -03:00
parent 0fb948c9f6
commit 84be24f274
3 changed files with 57 additions and 29 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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()