Fix post-registration navigation and add comprehensive registration UI tests
- 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>
This commit is contained in:
600
iosApp/MyCribUITests/RegistrationTests.swift
Normal file
600
iosApp/MyCribUITests/RegistrationTests.swift
Normal file
@@ -0,0 +1,600 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user