[coverage-85] Add HomeFiltersFlowTests, fix stuck activeModal on interactive sheet dismiss
FiltersModalView.swift was 0% covered. Reaching it via guest mode hit
the backend's App Attest simulator-bypass rejection (403
APP_ATTEST_VERIFICATION_FAILED on /api/public/session, confirmed via
curl - a pre-existing, out-of-repo backend issue already documented in
decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md), which
kept the guest address picker stuck showing a load-error sub-screen.
While chasing that, found a real bug in ContentView.swift:
.sheet(item: $appState.activeModal) had no onDismiss, so an
interactive swipe-to-dismiss never reset the bound item to nil -
anyone who swipes the address picker away without picking a location
leaves appState.activeModal stuck non-nil, silently breaking the next
modal presentation app-wide. Fixed with
onDismiss: { appState.activeModal = nil }.
Rewrote HomeFiltersFlowTests to use the authenticated QA account
instead of guest mode, routing around the backend-blocked guest wall
entirely. Also fixed a separate, real XCUITest issue: a plain .tap()
on the filter icon (inside Home's .offset()-transformed collapsing
header) reliably produced "Computed hit point {-1, -1}" - fixed via
coordinate(withNormalizedOffset:).tap().
Verified: HomeFiltersFlowTests passed clean across 2 consecutive
isolated runs. Full-suite regression run could not be completed this
round - the local environment stopped completing any instrumented
test launch afterward (reproduced across background/foreground,
clean DerivedData, simulator reboot, decoupled build/test, process
cleanup), unrelated to these changes. Documented in
decisions/2026-08-11-coverage-push-to-85-percent-status.md, with a
next-session TODO to run the full suite once the environment recovers.
This commit is contained in:
68
PediFoodsUITests/HomeFiltersFlowTests.swift
Normal file
68
PediFoodsUITests/HomeFiltersFlowTests.swift
Normal file
@@ -0,0 +1,68 @@
|
||||
import XCTest
|
||||
|
||||
/// Covers Home's filter sheet (FiltersModalView.swift, ~700 lines, was
|
||||
/// 0% covered), reachable via the search bar's filter icon
|
||||
/// (identifier "slider.horizontal.3"). Uses the authenticated QA account
|
||||
/// rather than guest mode - the guest address picker
|
||||
/// (PublicLocationPickerView) currently can't load its states/cities list
|
||||
/// at all, because the backend rejects the simulator's App Attest bypass
|
||||
/// with 403 APP_ATTEST_VERIFICATION_FAILED (confirmed directly via curl
|
||||
/// against /api/public/session, a pre-existing backend-side issue, see
|
||||
/// decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md). That
|
||||
/// leaves the guest address-picker sheet re-presenting itself indefinitely
|
||||
/// (HomeView+Data.loadGuestStores() keeps re-triggering it while no
|
||||
/// location is set), permanently covering Home. Logging in with the
|
||||
/// standing QA account swaps AddressPickerModalView to the
|
||||
/// App-Attest-free AddressesView instead, routing around the guest wall
|
||||
/// entirely.
|
||||
final class HomeFiltersFlowTests: XCTestCase {
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
XCUIApplication().logoutIfAuthenticated()
|
||||
}
|
||||
|
||||
func testFiltersSheetSelectionsAndApply() throws {
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
XCTAssertTrue(app.ensureLoggedIn(), "Login never completed")
|
||||
|
||||
// ensureLoggedIn can land on whichever tab it detected the
|
||||
// authenticated session from - switch explicitly.
|
||||
XCTAssertTrue(app.buttons["Home"].waitForExistence(timeout: 10))
|
||||
app.buttons["Home"].tap()
|
||||
|
||||
// The filter icon lives inside Home's collapsing header
|
||||
// (SearchBar, positioned with .offset(y: collapseProgress * -120))
|
||||
// - a plain .tap() was separately confirmed (while still chasing
|
||||
// the guest-mode blocker above) to sometimes resolve to an invalid
|
||||
// "Computed hit point {-1, -1}" for this transform-positioned
|
||||
// element. Tapping a normalized-offset coordinate on the element
|
||||
// bypasses XCUITest's automatic hit-point computation.
|
||||
let filterIcon = app.buttons.matching(identifier: "slider.horizontal.3").firstMatch
|
||||
XCTAssertTrue(filterIcon.waitForExistence(timeout: 10), "Filter icon never appeared on Home")
|
||||
filterIcon.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
|
||||
XCTAssertTrue(app.staticTexts["Filtros"].waitForExistence(timeout: 5), "Never reached the filters sheet")
|
||||
|
||||
// Sort option - just needs to be selectable, no assertion on the
|
||||
// resulting Home state (that's real backend store data, out of
|
||||
// scope here).
|
||||
let ratingSort = app.buttons["Avaliação"]
|
||||
if ratingSort.exists {
|
||||
ratingSort.tap()
|
||||
}
|
||||
|
||||
// Price tier - label is the raw "$"/"$$"/etc symbol.
|
||||
let mediumPrice = app.buttons["$$"]
|
||||
if mediumPrice.exists {
|
||||
mediumPrice.tap()
|
||||
}
|
||||
|
||||
app.buttons["Aplicar Filtros"].tap()
|
||||
|
||||
// Applying dismisses back to Home.
|
||||
XCTAssertTrue(app.textFields["Search menu, restaurant or craving"].waitForExistence(timeout: 10), "Never returned to Home after applying filters")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user