270 lines
10 KiB
Swift
270 lines
10 KiB
Swift
import XCTest
|
|
|
|
/// Comprehensive tests for authentication flows
|
|
final class AuthenticationUITests: BaseUITest {
|
|
|
|
// MARK: - Login Tests
|
|
|
|
func testLoginWithValidCredentials() {
|
|
// Given: User is on login screen
|
|
XCTAssertTrue(app.staticTexts["MyCrib"].exists)
|
|
|
|
// When: User enters valid credentials and taps login
|
|
login(username: "testuser", password: "TestPass123!")
|
|
|
|
// Then: User should be navigated to main screen
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10), "Should navigate to main tab view")
|
|
}
|
|
|
|
func testLoginWithInvalidCredentials() {
|
|
// Given: User is on login screen
|
|
XCTAssertTrue(app.staticTexts["MyCrib"].exists)
|
|
|
|
// When: User enters invalid credentials
|
|
login(username: "invaliduser", password: "WrongPassword!")
|
|
|
|
// Then: Error message should be displayed
|
|
let errorMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Invalid username or password'"))
|
|
XCTAssertTrue(errorMessage.firstMatch.waitForExistence(timeout: 5), "Should show error message")
|
|
|
|
// And: User should remain on login screen
|
|
XCTAssertTrue(app.staticTexts["MyCrib"].exists)
|
|
}
|
|
|
|
func testLoginWithEmptyFields() {
|
|
// Given: User is on login screen
|
|
let loginButton = app.buttons["Login"]
|
|
|
|
// When: User taps login without entering credentials
|
|
loginButton.tap()
|
|
|
|
// Then: Validation error should be shown
|
|
let usernameError = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Username is required'"))
|
|
XCTAssertTrue(usernameError.firstMatch.waitForExistence(timeout: 3), "Should show username required error")
|
|
}
|
|
|
|
func testPasswordVisibilityToggle() {
|
|
// Given: User has typed password
|
|
let passwordField = app.secureTextFields["Password"]
|
|
let textField = app.textFields["Password"]
|
|
let toggleButton = app.buttons.matching(identifier: "eye").firstMatch
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText("TestPassword")
|
|
|
|
// When: User taps the visibility toggle
|
|
toggleButton.tap()
|
|
|
|
// Then: Password should be visible as text
|
|
XCTAssertTrue(textField.exists, "Password should be visible")
|
|
|
|
// When: User taps toggle again
|
|
toggleButton.tap()
|
|
|
|
// Then: Password should be hidden again
|
|
XCTAssertTrue(passwordField.exists, "Password should be secure")
|
|
}
|
|
|
|
// MARK: - Registration Tests
|
|
|
|
func testRegistrationWithValidData() {
|
|
// Given: User is on login screen
|
|
let signUpButton = app.buttons["Sign Up"]
|
|
|
|
// When: User taps Sign Up
|
|
signUpButton.tap()
|
|
|
|
// Then: Registration screen should be displayed
|
|
assertNavigatedTo(title: "Create Account", timeout: 3)
|
|
|
|
// When: User fills in valid registration data
|
|
let timestamp = Int(Date().timeIntervalSince1970)
|
|
register(
|
|
username: "newuser\(timestamp)",
|
|
email: "newuser\(timestamp)@test.com",
|
|
password: "TestPass123!",
|
|
firstName: "Test",
|
|
lastName: "User"
|
|
)
|
|
|
|
// Then: User should be registered and shown verification screen
|
|
let verificationTitle = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Verify'"))
|
|
XCTAssertTrue(verificationTitle.firstMatch.waitForExistence(timeout: 10), "Should show verification screen")
|
|
}
|
|
|
|
func testRegistrationWithExistingUsername() {
|
|
// Given: User is on registration screen
|
|
let signUpButton = app.buttons["Sign Up"]
|
|
signUpButton.tap()
|
|
|
|
// When: User registers with existing username
|
|
register(
|
|
username: "existinguser",
|
|
email: "newemail@test.com",
|
|
password: "TestPass123!"
|
|
)
|
|
|
|
// Then: Error message should be displayed
|
|
let errorMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'username' OR label CONTAINS[c] 'already exists'"))
|
|
XCTAssertTrue(errorMessage.firstMatch.waitForExistence(timeout: 5), "Should show username exists error")
|
|
}
|
|
|
|
func testRegistrationWithInvalidEmail() {
|
|
// Given: User is on registration screen
|
|
let signUpButton = app.buttons["Sign Up"]
|
|
signUpButton.tap()
|
|
|
|
// When: User enters invalid email
|
|
let emailField = app.textFields["Email"]
|
|
let registerButton = app.buttons["Register"]
|
|
|
|
emailField.tap()
|
|
emailField.typeText("invalidemail")
|
|
|
|
registerButton.tap()
|
|
|
|
// Then: Email validation error should be shown
|
|
let errorMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'valid email'"))
|
|
XCTAssertTrue(errorMessage.firstMatch.waitForExistence(timeout: 3), "Should show email validation error")
|
|
}
|
|
|
|
func testRegistrationWithWeakPassword() {
|
|
// Given: User is on registration screen
|
|
let signUpButton = app.buttons["Sign Up"]
|
|
signUpButton.tap()
|
|
|
|
// When: User enters weak password
|
|
let timestamp = Int(Date().timeIntervalSince1970)
|
|
let usernameField = app.textFields["Username"]
|
|
let emailField = app.textFields["Email"]
|
|
let passwordField = app.secureTextFields["Password"]
|
|
let registerButton = app.buttons["Register"]
|
|
|
|
usernameField.tap()
|
|
usernameField.typeText("testuser\(timestamp)")
|
|
|
|
emailField.tap()
|
|
emailField.typeText("test\(timestamp)@test.com")
|
|
|
|
passwordField.tap()
|
|
passwordField.typeText("weak")
|
|
|
|
registerButton.tap()
|
|
|
|
// Then: Password validation error should be shown
|
|
let errorMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'password' AND (label CONTAINS[c] 'strong' OR label CONTAINS[c] 'at least')"))
|
|
XCTAssertTrue(errorMessage.firstMatch.waitForExistence(timeout: 3), "Should show password strength error")
|
|
}
|
|
|
|
// MARK: - Logout Tests
|
|
|
|
func testLogoutFlow() {
|
|
// Given: User is logged in
|
|
login(username: "testuser", password: "TestPass123!")
|
|
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10))
|
|
|
|
// When: User logs out
|
|
logout()
|
|
|
|
// Then: User should be returned to login screen
|
|
XCTAssertTrue(app.staticTexts["MyCrib"].waitForExistence(timeout: 5), "Should return to login screen")
|
|
XCTAssertTrue(app.buttons["Login"].exists, "Login button should be visible")
|
|
}
|
|
|
|
func testLogoutClearsUserData() {
|
|
// Given: User is logged in and has viewed some data
|
|
login(username: "testuser", password: "TestPass123!")
|
|
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10))
|
|
|
|
navigateToTab("Residences")
|
|
wait(seconds: 2) // Wait for data to load
|
|
|
|
// When: User logs out
|
|
logout()
|
|
|
|
// And: User logs back in
|
|
login(username: "testuser", password: "TestPass123!")
|
|
|
|
// Then: Fresh data should be loaded (not cached)
|
|
let loadingIndicator = app.activityIndicators.firstMatch
|
|
XCTAssertTrue(loadingIndicator.exists || app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Loading'")).firstMatch.exists,
|
|
"Should show loading state for fresh data")
|
|
}
|
|
|
|
// MARK: - Session Management Tests
|
|
|
|
func testSessionPersistence() {
|
|
// Given: User logs in
|
|
login(username: "testuser", password: "TestPass123!")
|
|
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10))
|
|
|
|
// When: App is terminated and relaunched
|
|
app.terminate()
|
|
app.launch()
|
|
|
|
// Then: User should still be logged in
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 5), "User session should persist")
|
|
}
|
|
|
|
func testLoginRedirectsVerifiedUser() {
|
|
// Given: Verified user logs in
|
|
login(username: "verifieduser", password: "TestPass123!")
|
|
|
|
// Then: User should go directly to main screen (not verification)
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10), "Verified user should skip verification")
|
|
}
|
|
|
|
func testLoginRedirectsUnverifiedUser() {
|
|
// Given: Unverified user logs in
|
|
login(username: "unverifieduser", password: "TestPass123!")
|
|
|
|
// Then: User should be shown verification screen
|
|
let verificationTitle = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Verify'"))
|
|
XCTAssertTrue(verificationTitle.firstMatch.waitForExistence(timeout: 10), "Unverified user should see verification screen")
|
|
}
|
|
|
|
// MARK: - Error Handling Tests
|
|
|
|
func testLoginWithNetworkError() {
|
|
// Note: This test requires network simulation or mocking
|
|
// For now, it's a placeholder for future implementation
|
|
|
|
// Given: Network is unavailable
|
|
// When: User attempts to login
|
|
// Then: Network error should be displayed
|
|
}
|
|
|
|
func testLoginRetryAfterError() {
|
|
// Given: User encountered a login error
|
|
login(username: "invaliduser", password: "WrongPassword!")
|
|
|
|
let errorMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Invalid'"))
|
|
XCTAssertTrue(errorMessage.firstMatch.waitForExistence(timeout: 5))
|
|
|
|
// When: User enters correct credentials
|
|
let usernameField = app.textFields["Username"]
|
|
let passwordField = app.secureTextFields["Password"]
|
|
let loginButton = app.buttons["Login"]
|
|
|
|
app.clearText(in: usernameField)
|
|
usernameField.typeText("testuser")
|
|
|
|
app.clearText(in: passwordField)
|
|
passwordField.typeText("TestPass123!")
|
|
|
|
loginButton.tap()
|
|
|
|
// Then: Login should succeed
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10), "Should login successfully after retry")
|
|
}
|
|
}
|