Remediate all P0-S priority findings from cross-platform architecture audit: - Harden token storage with EncryptedSharedPreferences (Android) and Keychain (iOS) - Add SSL pinning and certificate validation to API clients - Fix subscription cache race conditions and add thread-safe access - Add input validation for document uploads and file type restrictions - Refactor DocumentApi to use proper multipart upload flow - Add rate limiting awareness and retry logic to API layer - Harden subscription tier enforcement in SubscriptionHelper - Add biometric prompt for sensitive actions (Login, Onboarding) - Fix notification permission handling and device registration - Add UI test infrastructure (page objects, fixtures, smoke tests) - Add CI workflow for mobile builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
87 lines
2.7 KiB
Swift
87 lines
2.7 KiB
Swift
import XCTest
|
|
|
|
/// Page object for the registration screen.
|
|
///
|
|
/// Uses accessibility identifiers from `AccessibilityIdentifiers.Authentication`
|
|
/// to locate registration form elements and perform sign-up actions.
|
|
class RegisterScreen: BaseScreen {
|
|
|
|
// MARK: - Elements
|
|
|
|
var usernameField: XCUIElement {
|
|
app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
}
|
|
|
|
var emailField: XCUIElement {
|
|
app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
}
|
|
|
|
var passwordField: XCUIElement {
|
|
app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
}
|
|
|
|
var confirmPasswordField: XCUIElement {
|
|
app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
}
|
|
|
|
var registerButton: XCUIElement {
|
|
app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
}
|
|
|
|
var cancelButton: XCUIElement {
|
|
app.buttons[AccessibilityIdentifiers.Authentication.registerCancelButton]
|
|
}
|
|
|
|
/// Fallback element lookup for the register/create account button using predicate
|
|
var registerButtonByLabel: XCUIElement {
|
|
app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Register' OR label CONTAINS[c] 'Create Account'")).firstMatch
|
|
}
|
|
|
|
override var isDisplayed: Bool {
|
|
// Registration screen is visible if any of the register-specific fields exist
|
|
let usernameExists = usernameField.waitForExistence(timeout: timeout)
|
|
let emailExists = emailField.exists
|
|
return usernameExists || emailExists
|
|
}
|
|
|
|
// MARK: - Actions
|
|
|
|
/// Fills in the registration form and submits it.
|
|
/// Returns a MainTabScreen assuming successful registration leads to the main app.
|
|
@discardableResult
|
|
func register(username: String, email: String, password: String) -> MainTabScreen {
|
|
waitForElement(usernameField).tap()
|
|
usernameField.typeText(username)
|
|
|
|
emailField.tap()
|
|
emailField.typeText(email)
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText(password)
|
|
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(password)
|
|
|
|
// Try accessibility identifier first, fall back to label search
|
|
if registerButton.exists {
|
|
registerButton.tap()
|
|
} else {
|
|
registerButtonByLabel.tap()
|
|
}
|
|
|
|
return MainTabScreen(app: app)
|
|
}
|
|
|
|
/// Taps cancel to return to the login screen.
|
|
@discardableResult
|
|
func tapCancel() -> LoginScreen {
|
|
if cancelButton.exists {
|
|
cancelButton.tap()
|
|
} else {
|
|
// Fall back to navigation back button
|
|
tapBackButton()
|
|
}
|
|
return LoginScreen(app: app)
|
|
}
|
|
}
|