Skip to content

fix(tests): reset Photos access before the previous app instance lingers - #746

Merged
bmc08gt merged 1 commit into
mainfrom
fix/ui-test-photos-permission-reset
Sep 11, 2026
Merged

fix(tests): reset Photos access before the previous app instance lingers#746
bmc08gt merged 1 commit into
mainfrom
fix/ui-test-photos-permission-reset

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

AccessKeyBackupSmokeTests.testAccessKeyBackup_saveToPhotos fails in the full AllTargets plan run with Expected "Allow" Button to be hittable within 30.0s at BaseUITestCase.swift:101, and passes when run alone. In the plan it runs second, right after testAccessKeyBackup_copyToClipboard in the same runner process.

Two things differ from the isolated run:

  • setUp calls resetAuthorizationStatus(for: .photos) while the previous test's app instance can still be running. The XCUIAutomation header only says a running app "might get terminated while the reset occurs".
  • The plan marks FlipcashTests parallelizable, so xcodebuild runs every target, UI tests included, on a throwaway Clone 1 of iPhone 17. On that clone the Photos alert took 12.5s to become hittable (xcresult activities: "Save to Photos" tapped at +0, "Allow" tapped at +12.5s); on the base device it takes about 6s. A busier plan run leaves less headroom under the 30s wait.

The exact plan-run failure did not reproduce in class-level runs. Measured on the base device with a tccd log stream and a TCC.db poller, the reset deleted the kTCCServicePhotosAdd row and the alert appeared with the test alone, with the whole class after pre-launching the app, and after a fresh install where tccd logs bundleRecordWithBundleIdentifier failed ... -10814 and still publishes the delete.

Fix

Harness only, no app changes.

  • BaseUITestCase.setUp terminates the app before resetting permissions when the test resets any, so the reset runs against a stopped process.
  • New allowSystemAlertIfNeeded(timeout:orUntil:) polls up to 60s for either the springboard "Allow" button or the caller's settled condition, tapping Allow only when the alert shows, and fails with a message naming both outcomes otherwise.
  • testAccessKeyBackup_saveToPhotos uses it with !saveButton.exists as the settled condition, then keeps the existing success-state assertion.
  • Reflection 2026-09-09-ui-test-tcc-evidence-on-clones.md: a plan run's UI tests run on a clone, so the base simulator's TCC.db is not evidence about it.

`AccessKeyBackupSmokeTests.testAccessKeyBackup_saveToPhotos` fails in the
`AllTargets` plan run with `Expected "Allow" Button to be hittable within
30.0s` (`BaseUITestCase.swift:101`) while passing alone. In the plan it runs
right after `testAccessKeyBackup_copyToClipboard` in the same runner, so
`setUp` resets Photos access while the previous test's app instance can still
be running, and the reset API only promises that a running app "might" be
terminated during the reset. The plan run also executes UI tests on a
throwaway simulator clone, where the Photos alert took 12.5s to become
hittable against about 6s on the base device.

- `BaseUITestCase.setUp` terminates the app before resetting permissions.
- `allowSystemAlertIfNeeded(orUntil:)` waits up to 60s for either the
  springboard "Allow" button or the app moving on without one, and taps
  Allow only when it shows.
- `testAccessKeyBackup_saveToPhotos` uses it in place of the hard 30s wait.
- Reflection added: the base simulator's `TCC.db` says nothing about a plan
  run that used a clone.
@bmc08gt bmc08gt self-assigned this Sep 9, 2026
@bmc08gt
bmc08gt merged commit b1afd97 into main Sep 11, 2026
1 check passed
bmc08gt added a commit that referenced this pull request Sep 11, 2026
…discrete-curve

* origin/main: (27 commits)
  fix(database): share one SQLite writer per owner and take write locks up front (#759)
  feat(chat): declare the payment action on tip DM payments (#752)
  refactor(chat): drop the deprecated new_messages overlay (#757)
  feat(notifications): write prefetched messages into the shared store (#756)
  refactor(store): move the persistence layer into a shared FlipcashStore package (#755)
  feat(database): move the SQLite store into the App Group container (#754)
  feat(database): open the store on demand, close it on background (#753)
  feat(nse): extension crash reporting, a WAL checkpoint, and on-device push hooks (#751)
  feat(home): long-press the You tab to open the account switcher (#749)
  fix(tests): reset Photos access before the previous app instance lingers (#746)
  chore: bump version to 2026.9.2 (#745)
  revert: back out the Coinbase Stable Swapper authority migration (#747) (#750)
  fix(swap): follow the Coinbase Stable Swapper authority migration (#747)
  fix(tests): cancel a cash link through the details screen (#744)
  fix(chat): make the whole Send Cash pill tappable while it stands alone (#743)
  fix(username): drop a leading @ in the validator (#742)
  fix(chat): scope the send-button spring to the button (#741)
  fix(transactions): tighten the details card stack and drop the header badge (#740)
  fix(transactions): draw View in Chat as a card, not the primary action (#739)
  feat(chat): flash the message a reply-quote jump lands on (#738)
  ...

# Conflicts:
#	Code.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
#	FlipcashCore/Package.swift
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant