import 'package:flutter_test/flutter_test.dart'; import 'package:shuffle/features/auth/domain/auth_failure.dart'; import 'package:shuffle/features/auth/domain/email_link_type.dart'; import 'package:shuffle/features/auth/domain/resend_origin.dart'; void main() { group('KTO-01 Kriterium 6: resendFailureFor (F12)', () { const limited = AuthFailure.emailSendLimited(); test('check-email screen treats emailSendLimited as success', () { expect(resendFailureFor(limited, ResendOrigin.checkEmail), isNull); }); test('login screen shows the throttling hint', () { expect( resendFailureFor(limited, ResendOrigin.login), const AuthFailure.rateLimited(), ); }); test('F13: on the check-email screen unexpected (SMTP) is neutral', () { expect( resendFailureFor( const AuthFailure.unexpected(), ResendOrigin.checkEmail, ), isNull, ); for (final origin in ResendOrigin.values) { expect( resendFailureFor(const AuthFailure.emailNotConfirmed(), origin), isNull, ); } }); test('S4: at login (account proven) unexpected stays visible', () { expect( resendFailureFor(const AuthFailure.unexpected(), ResendOrigin.login), const AuthFailure.unexpected(), ); }); test('input errors stay visible', () { for (final origin in ResendOrigin.values) { expect( resendFailureFor(const AuthFailure.invalidEmail(), origin), const AuthFailure.invalidEmail(), ); } }); test('allowlisted failures stay visible', () { for (final origin in ResendOrigin.values) { expect( resendFailureFor(const AuthFailure.rateLimited(), origin), const AuthFailure.rateLimited(), ); expect( resendFailureFor(const AuthFailure.network(), origin), const AuthFailure.network(), ); } }); }); group('KTO-01 Kriterium 4: openEmailInputFailureFor (F12)', () { test('emailSendLimited counts as success', () { expect( openEmailInputFailureFor(const AuthFailure.emailSendLimited()), isNull, ); }); test( 'F13: unexpected (SMTP outage) and unknown failures count as success', () { for (final failure in [ const AuthFailure.unexpected(), const AuthFailure.emailNotConfirmed(), const AuthFailure.invalidCredentials(), const AuthFailure.linkInvalidOrExpired(), ]) { expect(openEmailInputFailureFor(failure), isNull, reason: '$failure'); } }, ); test('F13 allowlist: input, transport and IP throttling stay visible', () { for (final failure in [ const AuthFailure.invalidEmail(), const AuthFailure.weakPassword([WeakPasswordReason.length]), const AuthFailure.registrationRejected( reason: RegistrationRejectionReason.displayName, ), const AuthFailure.network(), const AuthFailure.rateLimited(), ]) { expect(openEmailInputFailureFor(failure), failure); } }); test('registrationRejected without a known reason is neutral', () { expect( openEmailInputFailureFor(const AuthFailure.registrationRejected()), isNull, ); }); test('rateLimited stays visible', () { expect( openEmailInputFailureFor(const AuthFailure.rateLimited()), const AuthFailure.rateLimited(), ); }); }); group('KTO-01 Kriterium 8: EmailLinkType.tryParse', () { test('maps email and signup to confirmation, recovery to recovery', () { expect(EmailLinkType.tryParse('email'), EmailLinkType.confirmation); expect(EmailLinkType.tryParse('signup'), EmailLinkType.confirmation); expect(EmailLinkType.tryParse('recovery'), EmailLinkType.recovery); }); test('rejects missing and unknown types', () { expect(EmailLinkType.tryParse(null), isNull); expect(EmailLinkType.tryParse(''), isNull); expect(EmailLinkType.tryParse('magiclink'), isNull); expect(EmailLinkType.tryParse('invite'), isNull); }); }); }