2 Commits

Author SHA1 Message Date
Trey T d5041492a9 test: add forceFreshLoginPerTest opt-in flag to AuthenticatedUITestCase
Android UI Tests / ui-tests (push) Has been cancelled
Default is `false` (current session-reuse behaviour) so tests reuse the
existing logged-in session — fast, and resilient to suites where the
current screen lacks a logout affordance (`UITestHelpers.ensureLoggedOut`
times out → tests fail before their bodies run).

Override to `true` in suites that observe transient `Invalid token` 401s
on POST/PATCH while reads continue to work. Recipe added after a 2026-05
incident where the API container was rebuilt mid-suite and in-memory
JWT tokens went stale; the diagnostic value is having an explicit lever
to reach for next time, not flipping the default.

Net effect on a clean simulator + stable API: 244/253 → 244/253 (no
behaviour change in the default path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 13:14:37 -05:00
admin ec5d93efab Merge pull request 'feat: bundle ID migration + gitea#2 task-cache fix (recovered from fix/task-cache-unification)' (#4) from feat/bundle-id-and-task-cache into master
Android UI Tests / ui-tests (push) Has been cancelled
Reviewed-on: #4
2026-05-01 20:48:28 -05:00
@@ -34,6 +34,23 @@ class AuthenticatedUITestCase: BaseUITestCase {
} }
} }
/// When `true`, every test in the suite forces a logout login cycle
/// in `setUp`, guaranteeing a freshly-issued auth token on each run.
///
/// Default is `false`: tests reuse the existing logged-in session
/// from the previous test in the same suite much faster (one login
/// per suite, not one per test) and resilient to suites where the
/// current screen has no logout affordance (`UITestHelpers.ensureLoggedOut`
/// times out the test fails before its body runs).
///
/// Override to `true` in suites that have observed transient
/// `Invalid token` 401s on POST/PATCH while reads continue to work.
/// The recipe was added after a 2026-05 incident where the API
/// container was rebuilt mid-suite and in-memory tokens went stale.
/// In normal CI runs against a stable API + freshly-erased simulator,
/// session reuse is the correct default.
var forceFreshLoginPerTest: Bool { false }
override func setUpWithError() throws { override func setUpWithError() throws {
guard TestAccountAPIClient.isBackendReachable() else { guard TestAccountAPIClient.isBackendReachable() else {
throw XCTSkip("Backend not reachable at \(TestAccountAPIClient.baseURL)") throw XCTSkip("Backend not reachable at \(TestAccountAPIClient.baseURL)")
@@ -41,27 +58,27 @@ class AuthenticatedUITestCase: BaseUITestCase {
try super.setUpWithError() try super.setUpWithError()
// If already logged in (tab bar visible), skip the login flow
let tabBar = app.tabBars.firstMatch let tabBar = app.tabBars.firstMatch
if tabBar.waitForExistence(timeout: defaultTimeout) { let alreadyLoggedIn = tabBar.waitForExistence(timeout: defaultTimeout)
// Already logged in just set up API session if needed
if needsAPISession {
guard let apiSession = TestAccountManager.loginSeededAccount(
username: apiCredentials.username,
password: apiCredentials.password
) else {
XCTFail("Could not login API account '\(apiCredentials.username)'")
return
}
session = apiSession
cleaner = TestDataCleaner(token: apiSession.token)
}
return
}
// Not logged in do the full login flow // Force-fresh path: log out (if needed) and re-authenticate per
UITestHelpers.ensureLoggedOut(app: app) // test so every test starts with a freshly-issued JWT. Catches
loginToMainApp() // server-side token invalidation that would otherwise surface
// mid-suite as opaque 401s on the first mutation call.
if forceFreshLoginPerTest {
if alreadyLoggedIn {
UITestHelpers.ensureLoggedOut(app: app)
} else {
UITestHelpers.ensureLoggedOut(app: app)
}
loginToMainApp()
} else if !alreadyLoggedIn {
// Legacy session-reuse path: only log in when not already in.
UITestHelpers.ensureLoggedOut(app: app)
loginToMainApp()
}
// (When `forceFreshLoginPerTest == false` AND we're already
// logged in, fall through with the existing session.)
if needsAPISession { if needsAPISession {
guard let apiSession = TestAccountManager.loginSeededAccount( guard let apiSession = TestAccountManager.loginSeededAccount(