- Fix RegisterView to call AuthenticationManager.login() after email verification so user is properly transitioned to home screen instead of returning to login - Fix ResidencesListView to load data when authentication state becomes true, ensuring residences load after registration/login - Add accessibility identifier to verification code field for UI testing - Add NSAppTransportSecurity exceptions for localhost/127.0.0.1 for local dev - Add comprehensive XCUITest suite for registration flow including: - Form validation tests (empty fields, invalid email, mismatched passwords) - Full registration and verification flow test - Logout from verification screen test - Helper scripts for test user cleanup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
601 lines
26 KiB
Swift
601 lines
26 KiB
Swift
import XCTest
|
|
#if os(macOS)
|
|
import Foundation
|
|
#endif
|
|
|
|
/// Comprehensive registration flow tests
|
|
/// Tests the complete registration and email verification flow
|
|
///
|
|
/// NOTE: Tests that require database access (fetchVerificationCode, cleanupTestUser)
|
|
/// use shell scripts that run on the host machine. These tests are designed to run
|
|
/// in the iOS Simulator with the backend running locally.
|
|
final class RegistrationTests: XCTestCase {
|
|
var app: XCUIApplication!
|
|
|
|
// Test user credentials - using timestamp to ensure unique users
|
|
private var testUsername: String {
|
|
return "testuser_\(Int(Date().timeIntervalSince1970))"
|
|
}
|
|
private var testEmail: String {
|
|
return "test_\(Int(Date().timeIntervalSince1970))@example.com"
|
|
}
|
|
private let testPassword = "TestPass123!"
|
|
|
|
override func setUpWithError() throws {
|
|
continueAfterFailure = false
|
|
app = XCUIApplication()
|
|
app.launch()
|
|
ensureLoggedOut()
|
|
}
|
|
|
|
override func tearDownWithError() throws {
|
|
// Clean up: logout if logged in
|
|
ensureLoggedOut()
|
|
app = nil
|
|
}
|
|
|
|
// MARK: - Helper Methods
|
|
|
|
private func ensureLoggedOut() {
|
|
UITestHelpers.ensureLoggedOut(app: app)
|
|
}
|
|
|
|
private func navigateToRegistration() {
|
|
let signUpButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Sign Up'")).firstMatch
|
|
XCTAssertTrue(signUpButton.waitForExistence(timeout: 5), "Sign Up button should exist on login screen")
|
|
signUpButton.tap()
|
|
sleep(1)
|
|
}
|
|
|
|
/// Dismisses the iOS Strong Password suggestion overlay if it appears
|
|
private func dismissStrongPasswordSuggestion() {
|
|
// Look for "Choose My Own Password" or similar button in the password suggestion
|
|
let chooseOwnPassword = app.buttons["Choose My Own Password"]
|
|
if chooseOwnPassword.waitForExistence(timeout: 2) {
|
|
chooseOwnPassword.tap()
|
|
sleep(1)
|
|
return
|
|
}
|
|
|
|
// Try alternate labels
|
|
let notNowButton = app.buttons["Not Now"]
|
|
if notNowButton.exists {
|
|
notNowButton.tap()
|
|
sleep(1)
|
|
return
|
|
}
|
|
|
|
// Try tapping outside the suggestion to dismiss it
|
|
let strongPasswordText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Strong Password'")).firstMatch
|
|
if strongPasswordText.exists {
|
|
// Tap somewhere else to dismiss
|
|
app.tap()
|
|
sleep(1)
|
|
}
|
|
}
|
|
|
|
/// Fixed test verification code - Django uses this code for emails starting with "test_" in DEBUG mode
|
|
/// This matches ConfirmationCode.TEST_VERIFICATION_CODE in the Django backend
|
|
private let testVerificationCode = "123456"
|
|
|
|
/// Note: cleanupTestUser should be called from command line after tests complete
|
|
/// Run: cd /Users/treyt/Desktop/code/MyCrib/myCribAPI && python manage.py shell -c "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.filter(email__startswith='test_').delete()"
|
|
private func cleanupTestUser(email: String) {
|
|
print("Cleanup test user: \(email)")
|
|
print("Run manually if needed: cd /Users/treyt/Desktop/code/MyCrib/myCribAPI && python manage.py shell -c \"from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.filter(email='\(email)').delete()\"")
|
|
}
|
|
|
|
// MARK: - Registration Form Tests
|
|
|
|
func testRegistrationScreenElements() {
|
|
// Given: User is on login screen
|
|
navigateToRegistration()
|
|
|
|
// Then: Registration form should have all expected elements
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
let cancelButton = app.buttons[AccessibilityIdentifiers.Authentication.registerCancelButton]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5), "Username field should exist")
|
|
XCTAssertTrue(emailField.exists, "Email field should exist")
|
|
XCTAssertTrue(passwordField.exists, "Password field should exist")
|
|
XCTAssertTrue(confirmPasswordField.exists, "Confirm password field should exist")
|
|
XCTAssertTrue(createAccountButton.exists, "Create Account button should exist")
|
|
XCTAssertTrue(cancelButton.exists, "Cancel button should exist")
|
|
}
|
|
|
|
func testRegistrationWithEmptyFields() {
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User taps Create Account without filling fields
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
XCTAssertTrue(createAccountButton.waitForExistence(timeout: 5))
|
|
createAccountButton.tap()
|
|
|
|
// Then: Error message should appear
|
|
sleep(2)
|
|
let errorExists = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'required' OR label CONTAINS[c] 'error' OR label CONTAINS[c] 'invalid'")).firstMatch.waitForExistence(timeout: 3)
|
|
XCTAssertTrue(errorExists, "Error message should appear for empty fields")
|
|
}
|
|
|
|
func testRegistrationWithInvalidEmail() {
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User fills form with invalid email
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText("testuser")
|
|
|
|
emailField.tap()
|
|
emailField.typeText("invalid-email") // Invalid email format
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText(testPassword)
|
|
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(testPassword)
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Then: Error message for invalid email should appear
|
|
sleep(2)
|
|
let errorExists = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'email' OR label CONTAINS[c] 'invalid'")).firstMatch.waitForExistence(timeout: 3)
|
|
XCTAssertTrue(errorExists, "Error message should appear for invalid email")
|
|
}
|
|
|
|
func testRegistrationWithMismatchedPasswords() {
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User fills form with mismatched passwords
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText("testuser")
|
|
|
|
emailField.tap()
|
|
emailField.typeText("test@example.com")
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText("Password123!")
|
|
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText("DifferentPassword123!") // Mismatched password
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Then: Error message for mismatched passwords should appear
|
|
sleep(2)
|
|
let errorExists = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'match' OR label CONTAINS[c] 'password'")).firstMatch.waitForExistence(timeout: 3)
|
|
XCTAssertTrue(errorExists, "Error message should appear for mismatched passwords")
|
|
}
|
|
|
|
func testRegistrationWithWeakPassword() {
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User fills form with weak password
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText("testuser")
|
|
|
|
emailField.tap()
|
|
emailField.typeText("test@example.com")
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText("weak") // Too short/weak password
|
|
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText("weak")
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Then: Error message for weak password should appear
|
|
sleep(2)
|
|
let errorExists = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'password' OR label CONTAINS[c] 'character' OR label CONTAINS[c] 'strong'")).firstMatch.waitForExistence(timeout: 3)
|
|
XCTAssertTrue(errorExists, "Error message should appear for weak password")
|
|
}
|
|
|
|
func testCancelRegistration() {
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User taps Cancel button
|
|
let cancelButton = app.buttons[AccessibilityIdentifiers.Authentication.registerCancelButton]
|
|
XCTAssertTrue(cancelButton.waitForExistence(timeout: 5))
|
|
cancelButton.tap()
|
|
|
|
// Then: Should return to login screen
|
|
sleep(1)
|
|
let welcomeText = app.staticTexts["Welcome Back"]
|
|
XCTAssertTrue(welcomeText.waitForExistence(timeout: 5), "Should return to login screen")
|
|
}
|
|
|
|
// MARK: - Full Registration Flow Tests
|
|
|
|
func testSuccessfulRegistrationAndVerification() {
|
|
// Use unique credentials for this test
|
|
let username = testUsername
|
|
let email = testEmail
|
|
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User fills in valid registration details
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText(username)
|
|
|
|
emailField.tap()
|
|
emailField.typeText(email)
|
|
|
|
// Handle strong password suggestion by dismissing it
|
|
passwordField.tap()
|
|
sleep(1)
|
|
|
|
// Dismiss the strong password suggestion if it appears
|
|
dismissStrongPasswordSuggestion()
|
|
|
|
// Now type the password
|
|
passwordField.tap()
|
|
passwordField.typeText(testPassword)
|
|
|
|
confirmPasswordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(testPassword)
|
|
|
|
// Submit registration
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Wait for verification screen to appear
|
|
let verifyEmailTitle = app.staticTexts["Verify Your Email"]
|
|
XCTAssertTrue(verifyEmailTitle.waitForExistence(timeout: 10), "Should navigate to email verification screen")
|
|
|
|
// Use the fixed test verification code
|
|
// Django uses "123456" for emails starting with "test_" when DEBUG=True
|
|
let verificationCode = testVerificationCode
|
|
print("Using test verification code: \(verificationCode)")
|
|
|
|
// Enter the verification code
|
|
let codeField = app.textFields[AccessibilityIdentifiers.Authentication.verificationCodeField]
|
|
XCTAssertTrue(codeField.waitForExistence(timeout: 5), "Verification code field should exist")
|
|
codeField.tap()
|
|
codeField.typeText(verificationCode)
|
|
|
|
// Submit verification
|
|
let verifyButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Verify'")).firstMatch
|
|
XCTAssertTrue(verifyButton.exists, "Verify button should exist")
|
|
verifyButton.tap()
|
|
|
|
// Then: Should navigate to main app screen (home/residences tab)
|
|
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10), "Should navigate to main app after successful verification")
|
|
|
|
// Verify we're on the home screen by checking for residences-related content
|
|
let homeScreenVisible = residencesTab.isSelected || app.navigationBars.containing(NSPredicate(format: "identifier CONTAINS[c] 'Residences' OR identifier CONTAINS[c] 'Home' OR identifier CONTAINS[c] 'Properties'")).firstMatch.exists
|
|
XCTAssertTrue(homeScreenVisible || residencesTab.exists, "Should be on home/residences screen after registration")
|
|
|
|
// Navigate to Profile tab and log out
|
|
let profileTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Profile'")).firstMatch
|
|
XCTAssertTrue(profileTab.waitForExistence(timeout: 5), "Profile tab should exist")
|
|
profileTab.tap()
|
|
sleep(1)
|
|
|
|
// Tap logout button
|
|
let logoutButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Logout' OR label CONTAINS[c] 'Log Out' OR label CONTAINS[c] 'Sign Out'")).firstMatch
|
|
XCTAssertTrue(logoutButton.waitForExistence(timeout: 5), "Logout button should exist on profile screen")
|
|
logoutButton.tap()
|
|
sleep(1)
|
|
|
|
// Confirm logout in alert if present
|
|
let alertLogoutButton = app.alerts.buttons["Log Out"]
|
|
if alertLogoutButton.waitForExistence(timeout: 3) {
|
|
alertLogoutButton.tap()
|
|
sleep(1)
|
|
}
|
|
|
|
// Verify we're back on login screen
|
|
let welcomeText = app.staticTexts["Welcome Back"]
|
|
XCTAssertTrue(welcomeText.waitForExistence(timeout: 5), "Should return to login screen after logout")
|
|
|
|
// Cleanup test user
|
|
cleanupTestUser(email: email)
|
|
}
|
|
|
|
func testRegistrationWithInvalidVerificationCode() {
|
|
// Use unique credentials for this test
|
|
let username = testUsername
|
|
let email = testEmail
|
|
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// Register a new user
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText(username)
|
|
|
|
emailField.tap()
|
|
emailField.typeText(email)
|
|
|
|
passwordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
passwordField.tap()
|
|
passwordField.typeText(testPassword)
|
|
|
|
confirmPasswordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(testPassword)
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Wait for verification screen
|
|
let verifyEmailTitle = app.staticTexts["Verify Your Email"]
|
|
XCTAssertTrue(verifyEmailTitle.waitForExistence(timeout: 10), "Should navigate to email verification screen")
|
|
|
|
// Enter an invalid verification code
|
|
let codeField = app.textFields[AccessibilityIdentifiers.Authentication.verificationCodeField]
|
|
XCTAssertTrue(codeField.waitForExistence(timeout: 5))
|
|
codeField.tap()
|
|
codeField.typeText("000000") // Invalid code
|
|
|
|
// Submit verification
|
|
let verifyButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Verify'")).firstMatch
|
|
verifyButton.tap()
|
|
|
|
// Then: Error message should appear
|
|
sleep(3)
|
|
let errorExists = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'invalid' OR label CONTAINS[c] 'error' OR label CONTAINS[c] 'incorrect'")).firstMatch.waitForExistence(timeout: 5)
|
|
XCTAssertTrue(errorExists, "Error message should appear for invalid verification code")
|
|
|
|
// Cleanup: Logout and delete test user
|
|
let logoutButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Logout'")).firstMatch
|
|
if logoutButton.exists {
|
|
logoutButton.tap()
|
|
sleep(2)
|
|
}
|
|
cleanupTestUser(email: email)
|
|
}
|
|
|
|
func testLogoutFromVerificationScreen() {
|
|
// Use unique credentials for this test
|
|
let username = testUsername
|
|
let email = testEmail
|
|
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// Register a new user
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText(username)
|
|
|
|
emailField.tap()
|
|
emailField.typeText(email)
|
|
|
|
passwordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
passwordField.tap()
|
|
passwordField.typeText(testPassword)
|
|
|
|
confirmPasswordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(testPassword)
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Wait for verification screen
|
|
let verifyEmailTitle = app.staticTexts["Verify Your Email"]
|
|
XCTAssertTrue(verifyEmailTitle.waitForExistence(timeout: 10), "Should navigate to email verification screen")
|
|
|
|
// When: User taps Logout button
|
|
let logoutButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Logout'")).firstMatch
|
|
XCTAssertTrue(logoutButton.waitForExistence(timeout: 5), "Logout button should exist on verification screen")
|
|
logoutButton.tap()
|
|
|
|
// Then: Should return to login screen
|
|
sleep(2)
|
|
let welcomeText = app.staticTexts["Welcome Back"]
|
|
XCTAssertTrue(welcomeText.waitForExistence(timeout: 5), "Should return to login screen after logout")
|
|
|
|
// Cleanup
|
|
cleanupTestUser(email: email)
|
|
}
|
|
|
|
func testVerificationCodeFieldValidation() {
|
|
// Use unique credentials for this test
|
|
let username = testUsername
|
|
let email = testEmail
|
|
|
|
// Given: User is on registration screen and registers
|
|
navigateToRegistration()
|
|
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText(username)
|
|
|
|
emailField.tap()
|
|
emailField.typeText(email)
|
|
|
|
passwordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
passwordField.tap()
|
|
passwordField.typeText(testPassword)
|
|
|
|
confirmPasswordField.tap()
|
|
sleep(1)
|
|
dismissStrongPasswordSuggestion()
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(testPassword)
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Wait for verification screen
|
|
let verifyEmailTitle = app.staticTexts["Verify Your Email"]
|
|
XCTAssertTrue(verifyEmailTitle.waitForExistence(timeout: 10))
|
|
|
|
// When: User tries to verify with incomplete code
|
|
let codeField = app.textFields[AccessibilityIdentifiers.Authentication.verificationCodeField]
|
|
XCTAssertTrue(codeField.waitForExistence(timeout: 5))
|
|
codeField.tap()
|
|
codeField.typeText("123") // Only 3 digits
|
|
|
|
// Then: Verify button should be disabled or show error
|
|
let verifyButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Verify'")).firstMatch
|
|
XCTAssertTrue(verifyButton.exists)
|
|
|
|
// The button might be disabled or tapping it shows an error
|
|
// Check that verification doesn't proceed with incomplete code
|
|
verifyButton.tap()
|
|
sleep(1)
|
|
|
|
// Should still be on verification screen
|
|
XCTAssertTrue(verifyEmailTitle.exists, "Should still be on verification screen with incomplete code")
|
|
|
|
// Cleanup
|
|
let logoutButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Logout'")).firstMatch
|
|
if logoutButton.exists {
|
|
logoutButton.tap()
|
|
sleep(2)
|
|
}
|
|
cleanupTestUser(email: email)
|
|
}
|
|
|
|
func testRegistrationWithExistingUsername() {
|
|
// This test requires an existing user in the database
|
|
// First, we need to ensure testuser exists
|
|
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User tries to register with existing username
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText("testuser") // Assuming this user already exists
|
|
|
|
emailField.tap()
|
|
emailField.typeText("newemail_\(Int(Date().timeIntervalSince1970))@example.com")
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText(testPassword)
|
|
|
|
confirmPasswordField.tap()
|
|
confirmPasswordField.typeText(testPassword)
|
|
|
|
let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
|
|
createAccountButton.tap()
|
|
|
|
// Then: Error message for existing username should appear
|
|
sleep(3)
|
|
let errorExists = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'exists' OR label CONTAINS[c] 'already' OR label CONTAINS[c] 'taken'")).firstMatch.waitForExistence(timeout: 5)
|
|
XCTAssertTrue(errorExists, "Error message should appear for existing username")
|
|
}
|
|
|
|
func testKeyboardNavigationDuringRegistration() {
|
|
// Given: User is on registration screen
|
|
navigateToRegistration()
|
|
|
|
// When: User navigates through fields using keyboard
|
|
let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
|
|
let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
|
|
let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
|
|
|
|
XCTAssertTrue(usernameField.waitForExistence(timeout: 5))
|
|
|
|
// Start with username field
|
|
usernameField.tap()
|
|
XCTAssertTrue(usernameField.hasKeyboardFocus, "Username field should have keyboard focus")
|
|
|
|
usernameField.typeText("testuser\n") // Press return to move to next field
|
|
|
|
sleep(1)
|
|
|
|
// Email field should now be focused (or at least exist)
|
|
XCTAssertTrue(emailField.exists, "Email field should exist")
|
|
|
|
emailField.tap()
|
|
emailField.typeText("test@example.com\n")
|
|
|
|
sleep(1)
|
|
|
|
// Password field should now be accessible
|
|
XCTAssertTrue(passwordField.exists, "Password field should exist")
|
|
}
|
|
}
|
|
|
|
// MARK: - XCUIElement Extension for keyboard focus
|
|
|
|
extension XCUIElement {
|
|
var hasKeyboardFocus: Bool {
|
|
return (value(forKey: "hasKeyboardFocus") as? Bool) ?? false
|
|
}
|
|
}
|