mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-19 21:00:40 +08:00
249 lines
8.7 KiB
Swift
249 lines
8.7 KiB
Swift
import Testing
|
|
import Foundation
|
|
@testable import StackAuth
|
|
|
|
@Suite("Error Handling Tests")
|
|
struct ErrorHandlingTests {
|
|
|
|
// MARK: - Authentication Errors
|
|
|
|
@Test("Should throw EmailPasswordMismatchError for wrong credentials")
|
|
func emailPasswordMismatchError() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
do {
|
|
try await app.signInWithCredential(email: "nonexistent@example.com", password: "wrong")
|
|
Issue.record("Expected EmailPasswordMismatchError")
|
|
} catch is EmailPasswordMismatchError {
|
|
// Expected
|
|
} catch let error as StackAuthErrorProtocol where error.code == "EMAIL_PASSWORD_MISMATCH" {
|
|
// Also acceptable
|
|
}
|
|
}
|
|
|
|
@Test("Should throw UserWithEmailAlreadyExistsError for duplicate sign up")
|
|
func userAlreadyExistsError() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
let email = TestConfig.uniqueEmail()
|
|
|
|
try await app.signUpWithCredential(email: email, password: TestConfig.testPassword)
|
|
try await app.signOut()
|
|
|
|
do {
|
|
try await app.signUpWithCredential(email: email, password: TestConfig.testPassword)
|
|
Issue.record("Expected UserWithEmailAlreadyExistsError")
|
|
} catch is UserWithEmailAlreadyExistsError {
|
|
// Expected
|
|
} catch let error as StackAuthErrorProtocol where error.code == "USER_EMAIL_ALREADY_EXISTS" {
|
|
// Also acceptable
|
|
}
|
|
}
|
|
|
|
@Test("Should throw UserNotSignedInError for unauthenticated access")
|
|
func userNotSignedInError() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
await #expect(throws: UserNotSignedInError.self) {
|
|
_ = try await app.getUser(or: .throw)
|
|
}
|
|
}
|
|
|
|
// MARK: - Error Properties
|
|
|
|
@Test("Should include error code in error")
|
|
func errorIncludesCode() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
do {
|
|
try await app.signInWithCredential(email: "nonexistent@example.com", password: "wrong")
|
|
Issue.record("Expected error")
|
|
} catch let error as StackAuthErrorProtocol {
|
|
#expect(!error.code.isEmpty)
|
|
#expect(error.code == "EMAIL_PASSWORD_MISMATCH")
|
|
}
|
|
}
|
|
|
|
@Test("Should include error message in error")
|
|
func errorIncludesMessage() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
do {
|
|
try await app.signInWithCredential(email: "nonexistent@example.com", password: "wrong")
|
|
Issue.record("Expected error")
|
|
} catch let error as StackAuthErrorProtocol {
|
|
#expect(!error.message.isEmpty)
|
|
}
|
|
}
|
|
|
|
@Test("Should have meaningful error description")
|
|
func errorHasMeaningfulDescription() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
do {
|
|
try await app.signInWithCredential(email: "nonexistent@example.com", password: "wrong")
|
|
Issue.record("Expected error")
|
|
} catch let error as StackAuthErrorProtocol {
|
|
let description = error.description
|
|
#expect(!description.isEmpty)
|
|
#expect(description.contains("EMAIL_PASSWORD_MISMATCH") || description.contains("password"))
|
|
}
|
|
}
|
|
|
|
// MARK: - Error Type Matching
|
|
|
|
@Test("Should match StackAuthError for unknown error codes")
|
|
func unknownErrorCodeMatchesStackAuthError() async throws {
|
|
// Create a StackAuthError with unknown code
|
|
let error = StackAuthError(code: "UNKNOWN_ERROR_CODE", message: "Test error")
|
|
|
|
#expect(error.code == "UNKNOWN_ERROR_CODE")
|
|
#expect(error.message == "Test error")
|
|
}
|
|
|
|
@Test("Should properly identify specific error types")
|
|
func identifySpecificErrorTypes() async throws {
|
|
let emailError = EmailPasswordMismatchError()
|
|
let userExistsError = UserWithEmailAlreadyExistsError()
|
|
let notSignedInError = UserNotSignedInError()
|
|
|
|
#expect(emailError.code == "EMAIL_PASSWORD_MISMATCH")
|
|
#expect(userExistsError.code == "USER_EMAIL_ALREADY_EXISTS")
|
|
#expect(notSignedInError.code == "USER_NOT_SIGNED_IN")
|
|
}
|
|
|
|
// MARK: - Error Recovery
|
|
|
|
@Test("Should be able to retry after authentication error")
|
|
func retryAfterAuthError() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
let email = TestConfig.uniqueEmail()
|
|
|
|
// Sign up
|
|
try await app.signUpWithCredential(email: email, password: TestConfig.testPassword)
|
|
try await app.signOut()
|
|
|
|
// First try with wrong password
|
|
do {
|
|
try await app.signInWithCredential(email: email, password: "WrongPassword123!")
|
|
} catch is EmailPasswordMismatchError {
|
|
// Expected
|
|
}
|
|
|
|
// Should still be able to sign in with correct password
|
|
try await app.signInWithCredential(email: email, password: TestConfig.testPassword)
|
|
|
|
let user = try await app.getUser()
|
|
#expect(user != nil)
|
|
}
|
|
|
|
// MARK: - Server-Side Errors
|
|
|
|
@Test("Should handle user not found for server operations")
|
|
func serverUserNotFound() async throws {
|
|
let app = TestConfig.createServerApp()
|
|
|
|
let fakeUserId = UUID().uuidString
|
|
let user = try await app.getUser(id: fakeUserId)
|
|
|
|
// Should return nil, not throw
|
|
#expect(user == nil)
|
|
}
|
|
|
|
@Test("Should handle team not found for server operations")
|
|
func serverTeamNotFound() async throws {
|
|
let app = TestConfig.createServerApp()
|
|
|
|
let fakeTeamId = UUID().uuidString
|
|
let team = try await app.getTeam(id: fakeTeamId)
|
|
|
|
// Should return nil, not throw
|
|
#expect(team == nil)
|
|
}
|
|
|
|
// MARK: - Password Errors
|
|
|
|
@Test("Should throw for weak password")
|
|
func weakPasswordError() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
let email = TestConfig.uniqueEmail()
|
|
|
|
do {
|
|
try await app.signUpWithCredential(email: email, password: "123")
|
|
Issue.record("Expected password error")
|
|
} catch is PasswordRequirementsNotMetError {
|
|
// Expected
|
|
} catch let error as StackAuthErrorProtocol where error.code == "PASSWORD_REQUIREMENTS_NOT_MET" || error.code == "PASSWORD_TOO_SHORT" {
|
|
// Also acceptable - different error codes for password issues
|
|
}
|
|
}
|
|
|
|
@Test("Should throw PasswordConfirmationMismatchError for wrong old password")
|
|
func wrongOldPasswordError() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
let email = TestConfig.uniqueEmail()
|
|
|
|
try await app.signUpWithCredential(email: email, password: TestConfig.testPassword)
|
|
|
|
let user = try await app.getUser()
|
|
|
|
do {
|
|
try await user?.updatePassword(oldPassword: "WrongOld123!", newPassword: "NewPass456!")
|
|
Issue.record("Expected PasswordConfirmationMismatchError")
|
|
} catch is PasswordConfirmationMismatchError {
|
|
// Expected
|
|
} catch let error as StackAuthErrorProtocol where error.code == "PASSWORD_CONFIRMATION_MISMATCH" {
|
|
// Also acceptable
|
|
}
|
|
}
|
|
}
|
|
|
|
@Suite("Project Tests")
|
|
struct ProjectTests {
|
|
|
|
// MARK: - Project Info Tests
|
|
|
|
@Test("Should get project info via client")
|
|
func getProjectViaClient() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
let project = try await app.getProject()
|
|
|
|
#expect(project.id == testProjectId)
|
|
}
|
|
|
|
@Test("Should get project info via server")
|
|
func getProjectViaServer() async throws {
|
|
let app = TestConfig.createServerApp()
|
|
|
|
let project = try await app.getProject()
|
|
|
|
#expect(project.id == testProjectId)
|
|
}
|
|
|
|
@Test("Should access project config")
|
|
func accessProjectConfig() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
let project = try await app.getProject()
|
|
|
|
// Config should exist (even if empty)
|
|
let _ = project.config
|
|
}
|
|
|
|
@Test("Should create client app with correct project ID")
|
|
func createClientAppWithProjectId() async throws {
|
|
let app = TestConfig.createClientApp()
|
|
|
|
let projectId = await app.projectId
|
|
#expect(projectId == testProjectId)
|
|
}
|
|
|
|
@Test("Should create server app with correct project ID")
|
|
func createServerAppWithProjectId() async throws {
|
|
let app = TestConfig.createServerApp()
|
|
|
|
let projectId = await app.projectId
|
|
#expect(projectId == testProjectId)
|
|
}
|
|
}
|