import Foundation import ManaCore import Testing @testable import ManaAuthUI @Suite("ForgotPasswordViewModel + ResetPasswordViewModel") @MainActor struct ForgotResetViewModelTests { // MARK: - ForgotPassword @Test("forgotPassword erfolgreich → .sent") func forgotSuccess() async { let mocked = makeMockedAuth() let model = ForgotPasswordViewModel( auth: mocked.auth, resetUniversalLink: URL(string: "https://cardecky.mana.how/auth/reset")! ) model.email = "u@x.de" let captured = MockURLProtocol.Capture() mocked.setHandler { request in captured.store(request) return (200, Data(#"{"success":true}"#.utf8)) } await model.submit() #expect(model.status == .sent) #expect(captured.request?.url?.path == "/api/v1/auth/forgot-password") } @Test("forgotPassword leere Email → canSubmit false") func forgotGuards() { let model = ForgotPasswordViewModel( auth: makeMockedAuth().auth, resetUniversalLink: URL(string: "https://x.test/auth/reset")! ) #expect(model.canSubmit == false) model.email = "u@x.de" #expect(model.canSubmit == true) } // MARK: - ResetPassword @Test("resetPassword erfolgreich → .done") func resetSuccess() async { let mocked = makeMockedAuth() let model = ResetPasswordViewModel(token: "tok123", auth: mocked.auth) model.newPassword = "Neu-987654321" model.confirmPassword = "Neu-987654321" mocked.setHandler { _ in (200, Data(#"{"success":true}"#.utf8)) } await model.submit() #expect(model.status == .done) #expect(model.newPassword == "") #expect(model.confirmPassword == "") } @Test("resetPassword mit abgelaufenem Token → .error") func resetTokenExpired() async { let mocked = makeMockedAuth() let model = ResetPasswordViewModel(token: "old", auth: mocked.auth) model.newPassword = "Neu-987654321" model.confirmPassword = "Neu-987654321" mocked.setHandler { _ in (400, Data(#"{"error":"TOKEN_EXPIRED","status":400}"#.utf8)) } await model.submit() if case let .error(message) = model.status { #expect(message == "Der Link ist abgelaufen. Bitte fordere einen neuen an.") } else { Issue.record("Expected .error, got \(model.status)") } } @Test("resetPassword validationHint bei Mismatch") func resetMismatch() { let model = ResetPasswordViewModel(token: "t", auth: makeMockedAuth().auth) model.newPassword = "lang-genug" model.confirmPassword = "anders-lang" #expect(model.validationHint == "Die Passwörter stimmen nicht überein.") #expect(model.canSubmit == false) } @Test("resetPassword canSubmit erfordert ≥8 Zeichen und Match") func resetCanSubmit() { let model = ResetPasswordViewModel(token: "t", auth: makeMockedAuth().auth) model.newPassword = "kurz" model.confirmPassword = "kurz" #expect(model.canSubmit == false) model.newPassword = "lang-genug" model.confirmPassword = "lang-genug" #expect(model.canSubmit == true) } }