Commit Graph

259 Commits

Author SHA1 Message Date
50c43fc810 Merge branch 'develop' into feature/ci/gitea-macos-runner 2026-09-11 11:37:19 -03:00
6fead38ad7 test(uitests): cover both add-on and plain-add product flows
The original helper only ever tapped the *first* product's add button
and assumed it went straight to Cart. That's the same single-path
assumption that produced the wrong 'product list never loaded'
diagnosis - the first product on this catalog ('Alcatra') has add-ons
and opens ProductDetailSheet ('Detalhes') instead of adding directly.
Fixing just the button selector would have hidden this and failed
differently on the next run.

Renamed reachCheckoutWithOneItem to reachCheckoutWithProducts(_:count:
Int = 3) and added addProduct(atIndex:in:), which taps the Nth
product's add button and branches on the real outcome: if
ProductDetailSheet appears, confirms via its own main action button
('Atualizar...') and waits for it to dismiss; otherwise the product
already added directly. Loops over the first 3 products (capped by the
actual button count) so both flows are exercised on every run,
regardless of which specific products the real catalog happens to give
add-ons to.

See decisions/2026-09-11-ui-test-shared-login-session.md follow-up.
2026-09-11 11:21:30 -03:00
2ebe97e078 fix(uitests): give the product add button an explicit accessibility identifier
quickDiagnostics finally showed the real state at the timeout: Store
Detail had genuinely loaded (store header, category tabs, a real priced
product 'Alcatra' R$ 14,00 all visible) - 'product list never loaded'
was simply the wrong diagnosis. The test was matching
app.images.matching(identifier: "plus") against the product row's add
button, relying entirely on SF Symbol systemName being exposed as an
implicit accessibility identifier - which wasn't holding on this Xcode
26/iOS 26 CI environment, and is inherently ambiguous anyway since
CartView's own quantity stepper reuses the same "plus" systemName.

Added a real .accessibilityIdentifier("storeDetailProductAddButton")
to the product row's add Button in StoreDetailView+Components.swift (an
app-source change, not just a test workaround), and updated the test to
match on that instead.

See decisions/2026-09-11-ui-test-shared-login-session.md follow-up.
2026-09-11 11:14:08 -03:00
ea6a3da78b fix(uitests): replace illegal key path with a closure in quickDiagnostics
'.map(\.label)' failed to build: XCUIElement.label is @MainActor-isolated,
and a bare key path literal must be formable from any isolation context,
which a main-actor-isolated property can't satisfy. This was a hard
compiler error (not just a concurrency warning), and it cascaded into a
flood of secondary diagnostics across the whole file/batch compile unit,
obscuring the actual cause. Replaced with a closure ('{ $0.label }'),
which isn't subject to that restriction.
2026-09-11 11:02:02 -03:00
6da8b05cfb test(uitests): embed live-state diagnostics in assertion messages, not a file
The file-based diagnostic dump never worked: PediFoodsUITests-Runner
runs as an app inside the simulator, sandboxed to that device's own
container filesystem. NSTemporaryDirectory() called from test code
resolves inside the simulator's data container, invisible to the host
shell's $TMPDIR a later CI step tried to cat - confirmed by the new
step printing 'No UI test diagnostic log was written.' every time.

Replaced with quickDiagnostics(_:), which builds a short live-state
summary (closed-store snackbar, spinning activity indicator, any open
alert, visible 'erro' text, first ~15 visible static texts) and
interpolates it directly into each of the three XCTAssertTrue failure
messages - the one channel already confirmed working end to end on
every run. message: is @autoclosure, so this costs nothing when the
assertion passes. Removed the dead file-write helper and the now-unused
CI step.

See decisions/2026-09-11-ui-test-shared-login-session.md follow-up.
2026-09-11 10:57:48 -03:00
3f99ebcba1 test(uitests): write failure diagnostics to a file, not print()
Confirmed (pasted full CI log around a timeout, searched for the
print()'d marker string, found nothing) that plain print() from inside
a UI test never reaches fastlane's xcodebuild log output on this
runner - its formatter only relays lines matching its own known
patterns and drops everything else.

CartCheckoutFlowTests now writes app.debugDescription to
NSTemporaryDirectory()+'pedifoods_uitest_diag.log' on each of its three
failure points (shared dumpDiagnostics helper, appending), clearing any
stale copy in class setUp(). test.yml gained a step after 'Run tests
with coverage' (if: always()) that cats that file when present - TMPDIR
is stable for the whole CI job, unlike the per-run-hashed workspace
path that broke the original screenshot attempt.

See decisions/2026-09-11-ui-test-shared-login-session.md follow-up.
2026-09-11 10:44:02 -03:00
1a7d5c3d51 test(uitests): replace broken scratch-path screenshots with debugDescription dumps
All three failure-path screenshot saves in this file wrote to a
hardcoded path from a different machine/session
(/private/tmp/claude-501/-Users-loverde-co-.../scratchpad), which
doesn't exist under the Mac mini runner's user account - try? silently
swallowed the write failure, so no diagnostic evidence was actually
produced on CI failures.

Replaced with app.debugDescription printed to stdout, which lands
directly in the CI log with no extra file access needed - same
technique already used in
decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md. Next
CartCheckoutFlowTests failure will show the actual accessibility
hierarchy at the point of timeout.
2026-09-11 10:21:43 -03:00
238b2ac7ba chore: bump CURRENT_PROJECT_VERSION to 2026.09.11.0.0.1
2026.0.25.0.0.1 is already live on the App Store. Bumped both the app
and NotificationServiceExtension targets together, keeping them matched.
2026-09-11 10:21:01 -03:00
9031f617a9 fix: match NotificationServiceExtension's CURRENT_PROJECT_VERSION to the app's
The extension's Debug/Release configs had CURRENT_PROJECT_VERSION = 1
(untouched Xcode default) while the main app target uses
2026.0.25.0.0.1, triggering 'The CFBundleVersion of an app extension
(1) must match that of its containing parent app' on every build/test
run. Both targets now build with the same CURRENT_PROJECT_VERSION.
2026-09-11 10:19:52 -03:00
d06e5013a8 test(uitests): drain accumulated cart once per class before checkout tests
The cart is on-device state (CartState/SessionStateStore), not purely
server-side - it survives app relaunches on the same simulator and has
been accumulating real quantities across every manual and automated run
against the 'MARIBA' test store, with no reset in between. No one-tap
'empty cart' UI action exists; the app's only full-clear path (the
'Trocar de loja?' alert's 'Limpar carrinho e adicionar') only fires when
switching to a genuinely different store, which this suite never does.

Added CartCheckoutFlowTests.setUp() (class) to drain the cart via its
own per-item 'minus' control in a capped loop before this class's tests
run, once per class rather than once per test, so every run starts from
a known-empty cart.

See decisions/2026-09-11-ui-test-shared-login-session.md follow-up.
2026-09-11 10:04:25 -03:00
84be24f274 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.
2026-09-11 10:00:51 -03:00
0fb948c9f6 fix(uitests): stop logging out after every authenticated test
All 7 authenticated-flow XCTestCase classes logged out for real in
tearDown, forcing a real OTP round trip against the production backend
on the next authenticated test. Under CI's back-to-back suite run this
produced ~9 real logins to the same QA phone number in ~9 minutes -
the first few succeeded (~30-40s each) but every one after that failed
to complete within timeout, cascading into 'Login never completed'
across CartCheckoutFlowTests, HomeFiltersFlowTests,
OrderDetailsFlowTests, SavedCardsFlowTests, UserProfileFlowTests.

Removed the per-test logout so the QA account's Keychain-backed session
persists across the whole suite (ensureLoggedIn already no-ops when
already authenticated). Moved the 'must start logged out' guarantee to
the two classes that actually need it - HomeGuestFlowTests and
ProfileLoggedOutFlowTests now force logout themselves right after
app.launch() via a small launch helper, instead of relying on whichever
authenticated class happened to run last.

See decisions/2026-09-11-ui-test-shared-login-session.md.
2026-09-11 09:45:26 -03:00
240cb288bf ci: prune unavailable simulators before running tests
Shared macOS runner accumulates orphaned simulator entries (registry
present, data dir missing on disk) which fail run_tests with 'Unable
to boot device because it cannot be located on disk'. Clean up before
every test run instead of requiring manual simctl intervention.
2026-09-11 09:18:46 -03:00
a5827f9136 fix: update performLCERequest for LCEssentials 2.0.2 API.request signature
LCEssentials 2.0.2 replaced request(url:params:method:headers:jsonEncoding:debug:)
with request(url:method:body:pathParams:headers:debug:timeoutInterval:networkServiceType:persistConnection:).
The pre-encoded params Data is now wrapped in RawBody to preserve the same
application/json Content-Type behavior that jsonEncoding: true used to set.
2026-09-11 09:09:54 -03:00
1b08ecb56e Update project.pbxproj 2026-09-11 08:54:01 -03:00
942f0a2c14 Merge branch 'main' into feature/ci/gitea-macos-runner 2026-09-10 20:34:19 -03:00
e86d16c9d2 [ci] Add ASC secrets presence check for debugging auth failure 2026-09-10 20:31:43 -03:00
75fa3c17b4 Merge pull request 'main' (#48) from main into develop
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#48
2026-09-10 20:10:09 -03:00
1f0e2ad86e Merge branch 'develop' into main 2026-09-10 20:10:00 -03:00
7666fa1512 Merge pull request 'feature/ci/gitea-macos-runner' (#47) from feature/ci/gitea-macos-runner into main
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#47
2026-09-10 20:09:06 -03:00
2ea8641ab2 Merge branch 'main' into feature/ci/gitea-macos-runner 2026-09-10 20:09:00 -03:00
d698049fab [ci] Move CI to native Mac mini runner, drop Bitrise
- Remove bitrise.yml (no longer used, replaced by Gitea Actions on
  a native macos-build:host runner - Docker VM-based macos-ctl/
  macos-release runners are dead per earlier session)
- test.yml: push-triggered on any branch except develop/release/main,
  runs fastlane tests (coverage) instead of raw xcodebuild
- beta.yml: PR-to-develop triggered, builds + uploads to TestFlight;
  drops the dead wake/sleep-macos-vm jobs, uses the archive-API
  checkout workaround (see go-gitea/gitea#21819), points at the real
  ci-build.keychain-db instead of the old ci-signing.keychain-db name
- release.yml removed: release/main run nothing automated per the
  agreed branch flow, promotion is manual
- Fastfile: add a tests lane (coverage) so the workflow just calls
  fastlane, matching LC Wallet's convention
2026-09-10 20:06:25 -03:00
8db72d6a12 [signing] Restore project.pbxproj settings wiped by xcodegen
Carry over pending signing/scheme fixes and .aider* gitignore entry
from the previous work-in-progress on this same base commit.
2026-09-10 20:06:12 -03:00
04bf67a212 Merge pull request 'main' (#45) from main into develop
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#45
2026-09-10 18:23:42 -03:00
bc5181fe21 Merge pull request 'fix/auth/payment-login-lockout' (#44) from fix/auth/payment-login-lockout into main
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#44
2026-09-10 18:22:39 -03:00
Daniel Arantes Loverde
1275fbee7a [signing] Restore project.pbxproj settings wiped by xcodegen
Running 'xcodegen generate' to register a new test file reverted every
setting that lives in project.pbxproj but is missing or stale in
project.yml. Restored the file from its known-good state and re-added only
the four PublicStoreDistanceTests.swift references by hand.

What xcodegen had destroyed:
- TargetAttributes gained DevelopmentTeam = "" on the app, the extension
  and the unit tests, which blanks the Team in Xcode's Signing UI so the
  provisioning profile no longer resolves.
- APP_ATTEST_ENVIRONMENT = production removed entirely.
- NSLocationWhenInUseUsageDescription replaced with the English string from
  project.yml, dropping the pt-BR one shipped for App Review.
- CURRENT_PROJECT_VERSION reset from 2026.0.25.0.0.1 to 1.

Verified the file now differs from the known-good state by exactly the four
new test-file lines, and that all four items above are back.
2026-08-27 16:59:54 -03:00
Daniel Arantes Loverde
a0e4375914 [public-store-distance] Consume the public distance contract, stop labelling it as unavailable
Guest browsing showed 'Distância indisponível' on every store card and a
'--' tile on store detail, because the public locator response carries no
distance and StoreSummary.init(publicItem:) hardcoded nil.

Backend contract (docs/plans/public-store-distance-consumer.md): distance
is a number, never null, 0 means unavailable. Implemented app-side ahead of
the backend - every change is forward-compatible, and the part that removes
the broken label works with no backend at all.

- PublicStoreListItem / PublicStoreDetail: + distance (optional, so today's
  responses without the field still decode).
- StoreSummary.init(publicItem:): normalize the 0 sentinel to nil, so one
  representation of 'unknown' reaches the label and the max-distance filter.
- fetchStoreDetail: send state/city from GuestLocationStore by default -
  the server needs them to resolve the city centroid.
- formatDistance: empty string for nil/0/negative. It previously returned
  'Distância indisponível' for nil, and - found by the new test - '0 m' for
  0 and '-1000 m' for a negative.
- StoreCard: drop the distance segment and its '·' separator together,
  otherwise the row ended in a dangling separator.
- StoreDetailView: drop the DISTÂNCIA tile and its divider instead of '--'.

Also fixes the same label in the authenticated flow when the user declined
location and has no address coordinates.

Tests: PublicStoreDistanceTests (decode with/without the field, passthrough,
0 normalization) + the empty case in HomeViewFilteringTests.
2026-08-27 16:33:01 -03:00
Daniel Arantes Loverde
0f0672f18d [auth-payment-login-lockout] Unify auth back button and animate the flow entry
- RegistrationView / LoginEmailView / OtpView: pushed with no nav bar, so
  they showed the oversized iOS 26 system glass back button. Wrapped each
  in LCENavigationView with the standard AppBackButtonIcon, matching
  LoginView and every other screen. Dropped the now-dead colorScheme dark
  branches and forced .preferredColorScheme(.light) (app has no dark
  theme).
- ContentView: root .auth <-> .main switched with no transition. Added
  .move transitions on both branches and wrapped enterAuthFlow() /
  LoginView's back action in withAnimation, so opening auth from Profile's
  'Entrar ou Cadastrar' now slides in and back slides out.
- ProfileLoggedOutFlowTests: new test asserting the pushed auth screens
  carry the LCENavigationView back button.
2026-08-27 10:59:06 -03:00
Daniel Arantes Loverde
21250ec2b9 [signing] Restore LC provisioning profiles and sync project.yml
I reverted project.pbxproj earlier to drop Xcode's objectVersion churn
and wiped the manual signing config with it. Restored.

- project.pbxproj: back to the LC Prov profile set (Dev/Dist for the app,
  Dev/Dist Push for NotificationService), CODE_SIGN_STYLE = Manual on all
  targets - byte-identical to fix/signing/notification-extension-distribution.
- project.yml: was still pointing at the old 'PediFoods Dev/Dist Prov
  Prof' names and CODE_SIGN_STYLE Automatic for the extension. Synced to
  the same LC Prov set so 'xcodegen generate' reproduces the signing
  instead of reverting it. Verified: regenerating from this project.yml
  yields the same CODE_SIGN_* / PROVISIONING_PROFILE_SPECIFIER settings.
2026-08-27 10:38:28 -03:00
Daniel Arantes Loverde
57103c637a [auth-payment-login-lockout] Make auth intro a clean screen with a back button
App Review rejected the 2026-08 build: tapping checkout as a guest
switched root to .auth, which replaced the whole UI with LoginView as the
NavigationStack root - no nav bar, no back, no dismiss. User was trapped.

- LoginView: rebuilt as a static screen in LCENavigationView with a back
  button that sets root = .main, a 'Criar conta' and an 'Entrar' button,
  and 'Termos de Uso' / 'Politica de Privacidade' links. Added #Preview.
- Forced .preferredColorScheme(.light) and fixed DS colors (the app has
  no dark theme, so system dark mode was inverting the nav bar / title).
- Removed the entry-reveal animation machinery (heroVisible/textVisible/
  buttonVisible/token/prepare flags across LoginView, AuthFlowView,
  ContentView) - dead since guest browsing shipped and the root cause of
  the 2026-08-06 'content stuck hidden' bug.
- enterAuthFlow() is now just root = .auth.
- UITestSupport.ensureLoggedIn taps 'Entrar' (new label).
- ProfileLoggedOutFlowTests: new test covering the choices and the way
  back out of .auth.
- Localizable.xcstrings: catalog caught up to the new/removed strings.
2026-08-27 10:31:39 -03:00
Daniel Arantes Loverde
662f7d6ebd Merge branch 'fix/home/header-categories-spacing' 2026-08-24 15:51:45 -03:00
Daniel Arantes Loverde
d969cca8b3 [lcenavigationview-adoption] Center Orders empty-state text, not left
Previous fix's VStack-level .frame(maxWidth: .infinity, alignment:
.leading) fixed the width but over-applied .leading to the empty
text too. Give it its own centered frame instead, matching the
isLoading/errorMessage branches right above it.
2026-08-24 15:30:37 -03:00
Daniel Arantes Loverde
033613ac40 [lcenavigationview-adoption] Fix Orders empty state shrinking to content width
The empty-orders branch ("Nenhum pedido encontrado.") had no
.frame(maxWidth: .infinity), unlike the loading/error branches -
ScrollView sizes to its content's intrinsic width, so the whole
container (and its background) shrank to the text's width, leaving
the real black window visible on both sides. Forces the VStack (and
ScrollView) to always fill width regardless of which branch renders.
2026-08-24 15:24:52 -03:00
Daniel Arantes Loverde
29c80d06af [lcenavigationview-adoption] Suppress glass button chrome via .buttonStyle(.plain)
Cascades .buttonStyle(.plain) down from each LCENavigationView
instance instead of waiting on the LCEssentials package fix
(committed separately, unpublished: LC_Essentials commit 8b0f650) to
be released and this repo's Package.resolved bumped. Overrides
iOS 26's automatic Liquid Glass chrome on LCENavigationView's
internal nav buttons - including the invisible backfilled mirror
button on whichever side has no real action - without affecting any
button that already sets its own explicit style closer to itself.
2026-08-24 15:18:57 -03:00
Daniel Arantes Loverde
18497b017a [lcenavigationview-adoption] Fix black nav bar background, add Cart title wrap
setNavigationBarBackgroundColor was never called on the 15 screens
adopted in 3456184, so it stayed at the default .clear and the real
window background (black) showed through. Set it to
AppColors.backgroundLight on all of them, matching each screen's own
actual content background. Also wraps CartView's title in
LCENavigationView for consistency with the rest of the app - no
setLeftButton since Cart is a tab root, no back button needed.

The other reported bug (empty right-button slot rendering a visible
glass circle) is fixed in LCEssentials itself (separate repo,
commit 8b0f650 on fix/navigation/liquid-glass-button-chrome) but
won't take visual effect here until that's published and this
repo's Package.resolved is bumped to point at it.
2026-08-24 14:50:46 -03:00
Daniel Arantes Loverde
afa5b87da0 Fix again 2026-08-24 14:40:25 -03:00
Daniel Arantes Loverde
345618426f [lcenavigationview-adoption] Adopt LCENavigationView across 15 screens
Standardizes the back button to a single shared component
(AppBackButtonIcon, 32x32/14pt) instead of ~16 hand-duplicated
52x52/24pt copies, and wires each screen through LCENavigationView
per this project's mandatory-usage rule. Home and Store Detail
intentionally excluded - both have bespoke header designs (collapsing
header, hero-image overlay) this change would visually disrupt.
2026-08-24 14:35:48 -03:00
Daniel Arantes Loverde
dae3b6f9d5 Fix header space 2026-08-24 14:03:36 -03:00
Daniel Arantes Loverde
394d53df91 [home-header-spacing] Remove redundant top padding above Categorias
contentTopSpacing (18pt) was stacked on top of the content VStack's
own 24pt inter-section spacing, giving header-to-Categorias a wider
gap (42pt) than every other section-to-section gap in Home (24pt).
Dropping it to 0 makes the gap consistent with the rest of the
screen.
2026-08-24 13:35:32 -03:00
59ec6ffd6f Merge pull request 'feature/push/opt-in-prompts' (#43) from feature/push/opt-in-prompts into main
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#43
2026-08-24 11:57:48 -03:00
Daniel Arantes Loverde
be38499759 [logged-out-auth-intro] Merge main into opt-in-prompts, keep enterAuth-closure UX
ProfileLoggedOutView conflict: kept this branch's simpler
enterAuth()-closure version over main's inline-embedded LoginView
(fix/profile/logged-out-auth-intro, predates the login-entry-
animation-bug fix). That bug was the actual reason the separate-
screen approach looked broken; it's already fixed here
(decisions/2026-08-06-login-entry-animation-bug.md), so the simpler
pattern works without re-threading a root binding through
MainTabView/ProfileLoggedOutView, which this branch deliberately
removed in favor of the closure. Ported the location-usage-
description Portuguese copy and the entitlements additions
(aps-environment, location.push) from main.
2026-08-24 11:48:27 -03:00
Daniel Arantes Loverde
9cb3654eb8 [logged-out-auth-intro] Merge into main, resolve entitlements/pbxproj conflicts
Union of both branches' entitlements (aps-environment + location.push
from this branch, App Attest CDhash opt-in from PR #41). Signing
settings resolved to Manual/Apple Distribution/AppStore profile -
this branch independently introduced the same Automatic/Apple
Development regression as PR #41 (see e93ccd2); one line
(PROVISIONING_PROFILE_SPECIFIER) merged silently to the broken value
without a marked conflict, caught by manual review and corrected
alongside the marked conflicts.
2026-08-24 11:42:00 -03:00
Daniel Arantes Loverde
e93ccd2f45 [app-attest-env] Restore Distribution/Manual signing on Release after PR #41
PR #41's App Attest environment fix (0bfdbb5) changed the Release
config's code signing from Manual/Apple Distribution/AppStore
provisioning profile to Automatic/Apple Development/no profile -
described in its own commit message as switching "local signing to
automatic" for App Attest testing, but applied to the same
config CI archives from for App Store submission. Automatic signing
needs an interactive Apple ID session (headless CI can't do that -
see docs/ci-cd/macos-runner-appstore-delivery.md section 2), and an
Apple Development identity can't produce an App-Store-uploadable
archive. Restores the prior signing settings, keeps the App Attest
environment fix itself untouched.
2026-08-24 11:40:15 -03:00
Daniel Arantes Loverde
3f09589f32 [app-attest-env] Merge production-environment fix into opt-in-prompts, port to flat layout
Resolves the App Attest env/entitlements changes onto the flattened
PediFoods.xcodeproj structure (Darwin/PediFoods.xcodeproj no longer
exists on this branch). Also restores Release signing to Manual /
Apple Distribution / AppStore provisioning profile - the merged-in
fix had switched it to Automatic / Apple Development, which breaks
headless CI archiving.
2026-08-24 11:39:23 -03:00
0c398157a7 Merge pull request 'fix/app-attest/production-environment' (#41) from fix/app-attest/production-environment into main
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#41
2026-08-24 11:04:18 -03:00
Daniel Arantes Loverde
2a934483fd [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.
2026-08-12 22:41:26 -03:00
Daniel Arantes Loverde
b68cd92307 [batch-f] Extend CardSelectionSheet test into PaymentCardView
testConfirmarEPagarWithCreditCardOpensCardSelectionWithoutSubmitting now
also taps CardSelectionSheet's "Adicionar novo cartão", which opens
PaymentCardView (CheckoutView.swift's own card-entry form - a distinct
struct from AddCardFormView.swift, which is a separate screen reached
from Profile -> Meus Cartões and already covered). Doesn't fill or
submit anything, just reaches the form and dismisses back through both
sheets.

Extracted the shared "x" close-button dismiss logic (used by both
CardSelectionSheet and PaymentCardView) into a private
dismissViaCloseButton helper.

Verified stable across 2 consecutive class-level runs.
2026-08-12 10:43:47 -03:00
Daniel Arantes Loverde
fff087c402 [batch-f] Add CardSelectionSheet test, fix product-row plus-button bug
Adds testConfirmarEPagarWithCreditCardOpensCardSelectionWithoutSubmitting:
selecting Cartão de Crédito and tapping "Confirmar e Pagar" opens
CardSelectionSheet (a separate struct in CheckoutView.swift) rather than
submitting an order - confirmed by reading
CheckoutView+Logic.handleConfirmPaymentTap(), which returns early before
any order-creation code when useInAppPayment && paymentMethod ==
.creditCard. Dismissed via the sheet's own close button, never selects a
card or submits anything, consistent with the earlier explicit user
direction not to create real order data during this coverage push.

Real bug found and fixed: reachCheckoutWithOneItem's product "+" button
selector (app.buttons.matching(identifier: "plus")) is the same class
of bug already fixed for the tab bar's cart icon - once a product's
quantity is > 0, its outer Button's identifier moves off itself onto a
nested Image (the row's own quantity Text takes over the Button's
accessible identity). This broke today specifically because the
standing QA account's cart has genuinely accumulated real quantities
across many runs, eventually leaving no untouched (quantity == 0)
product for the old selector to find - confirmed via screenshot showing
the "+" controls clearly rendered on screen while the buttons-only
query found nothing. Fixed by targeting the nested Image's identifier
directly (app.images.matching(identifier: "plus")), same fix pattern as
the cart-tab icon. This is shared by all three tests in the file via
reachCheckoutWithOneItem.

Also bumped two real-network timeouts based on trace evidence (not
guesses): store-detail load 15s -> 25s, OTP-request-to-Verificação-screen
15s -> 25s in UITestSupport.ensureLoggedIn.

Verified: the new test passes consistently in isolation and alongside
the other two tests in the class. One remaining flake
(testAddProductToCartAndReachCheckout hitting "Login never completed"
when run back-to-back with two other real-login tests in the same
invocation) confirmed via isolated rerun to be real backend load from
three consecutive real login/logout cycles, not a code regression -
passes cleanly alone.
2026-08-11 17:23:25 -03:00
Daniel Arantes Loverde
77bf276a5f [batch-f] Extend Checkout coverage: payment method selection + Alterar
Adds testCheckoutPaymentMethodSelectionAndAddressAlterar, exercising
CheckoutView's payment-method row selection and the address picker's
"Alterar" entry point without ever tapping "Confirmar e Pagar" -
deliberately not submitting a real order (explicit user direction:
cover the screen, don't create real order data in the QA account).

Extracted the shared reach-checkout steps from
testAddProductToCartAndReachCheckout into a private helper,
reachCheckoutWithOneItem, reused by both tests.

Fixed the same "not hittable" Back-button bug (already documented in
UITestSupport.swift) inline here too - tapping a Back button that
exists but is mid pop-transition throws a fatal, uncatchable failure;
needs an .isHittable check with a short poll, not just .exists.

Verified stable across 2 consecutive class-level runs.
2026-08-11 15:43:59 -03:00
Daniel Arantes Loverde
7702836fe7 migration 2026-08-11 13:22:02 -03:00