import XCTest /// Covers Store Detail -> add to cart -> Cart -> Checkout, the biggest /// remaining zero-coverage surface (CheckoutView.swift alone is ~5000 /// lines). Requires the standing QA account to have a real saved address /// so Home shows a real store list - see /// decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md. final class CartCheckoutFlowTests: XCTestCase { override func setUpWithError() throws { continueAfterFailure = false } override func tearDownWithError() throws { XCUIApplication().logoutIfAuthenticated() } func testAddProductToCartAndReachCheckout() throws { let app = XCUIApplication() app.launch() try reachCheckoutWithOneItem(app) } /// Exercises CheckoutView's payment-method selection and the address /// picker's "Alterar" entry point without ever tapping "Confirmar e /// Pagar" - deliberately not submitting a real order (per explicit /// user direction: cover the screen, don't create real order data). func testCheckoutPaymentMethodSelectionAndAddressAlterar() throws { let app = XCUIApplication() app.launch() try reachCheckoutWithOneItem(app) XCTAssertTrue(app.staticTexts["MÉTODO DE PAGAMENTO"].waitForExistence(timeout: 5)) // PIX is the default selection; only tap an alternative if this // store's real catalog actually offers one - don't assume Cartão // de Crédito exists (in-app payment methods depend on real store // config, already found to vary - see the standing-account state // notes in decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md). let creditCardRow = app.buttons.matching(NSPredicate(format: "label CONTAINS[c] %@", "Cartão de Crédito")).firstMatch if creditCardRow.exists { creditCardRow.tap() } XCTAssertTrue(app.staticTexts["TIPO DE ENTREGA"].waitForExistence(timeout: 5)) app.buttons["Alterar"].tap() XCTAssertTrue( app.staticTexts["Meus Endereços"].waitForExistence(timeout: 10), "Alterar never opened the address picker" ) // Dismiss without changing anything, back to Checkout. .isHittable, // not just .exists: a Back button that exists but is mid-transition // throws a fatal, uncatchable "not hittable" failure on tap - same // issue already fixed in UITestSupport.reachProfileTabRegardlessOfAuthState. // Poll briefly since the push-in animation can still be settling // right after "Meus Endereços" first becomes visible. let backButton = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch var dismissed = false for _ in 0..<10 { if backButton.exists, backButton.isHittable { backButton.tap() dismissed = true break } usleep(200_000) } if dismissed == false { app.swipeDown() } if app.staticTexts["Finalizar Pedido"].waitForExistence(timeout: 10) == false { let dir = "/private/tmp/claude-501/-Users-loverde-co-Documents-Loverde-JOBs-Producao-Loverde-Co-LC-RAG-Struct-projects-PediFoods-ios/4a9ec4f7-c3ad-4cf5-8dad-073446f6fd81/scratchpad" try? app.screenshot().pngRepresentation.write(to: URL(fileURLWithPath: "\(dir)/after_alterar_dismiss.png")) } XCTAssertTrue(app.staticTexts["Finalizar Pedido"].exists, "Never returned to Checkout") // Deliberately not tapping "Confirmar e Pagar" - see doc comment. } private func reachCheckoutWithOneItem(_ app: XCUIApplication) throws { XCTAssertTrue(app.ensureLoggedIn(), "Login never completed") // ensureLoggedIn can land on whichever tab it detected the // authenticated session from (e.g. Profile, if already logged in // from a previous test) rather than Home - switch explicitly. XCTAssertTrue(app.buttons["Home"].waitForExistence(timeout: 10)) app.buttons["Home"].tap() // The store card is one merged tappable element (name + category + // distance + status all combine into its accessibility label), not // a plain static text. let storeCard = app.buttons.matching(NSPredicate(format: "label CONTAINS[c] %@", "MARIBA")).firstMatch if storeCard.waitForExistence(timeout: 15) == false { let dir = "/private/tmp/claude-501/-Users-loverde-co-Documents-Loverde-JOBs-Producao-Loverde-Co-LC-RAG-Struct-projects-PediFoods-ios/4a9ec4f7-c3ad-4cf5-8dad-073446f6fd81/scratchpad" try? app.screenshot().pngRepresentation.write(to: URL(fileURLWithPath: "\(dir)/no_store_card.png")) } XCTAssertTrue(storeCard.exists, "Expected store card never appeared on Home") storeCard.tap() // A plain (non-addon, non-pizza) product row's "+" button adds // directly with no sheet - identified by its SF Symbol name like // the rest of this app's icon-only controls (person.fill, etc). let addButton = app.buttons.matching(identifier: "plus").firstMatch XCTAssertTrue(addButton.waitForExistence(timeout: 15), "Store Detail's product list never loaded") addButton.tap() // Once the cart has items, the tab bar button's accessible label // becomes just the badge count ("4") instead of "Shopping Cart" - // confirmed via hierarchy dump (SwiftUI's accessibility-children // combining dropped the nested Image's default "Shopping Cart" // label entirely once a sibling Text badge was added). The nested // "cart.fill" Image keeps its identifier regardless, so target // that directly rather than the outer button. let cartTab = app.images.matching(identifier: "cart.fill").firstMatch XCTAssertTrue(cartTab.waitForExistence(timeout: 5)) cartTab.tap() XCTAssertTrue(app.staticTexts["Meu Carrinho"].waitForExistence(timeout: 10)) XCTAssertFalse(app.staticTexts["Seu carrinho está vazio"].exists, "Cart still shows empty after adding a product") app.buttons["Ir para o Pagamento"].tap() XCTAssertTrue(app.staticTexts["Finalizar Pedido"].waitForExistence(timeout: 10), "Never reached Checkout") } }