feat(auth): add sendCodeSilently with isSending state
This commit is contained in:
@@ -16,6 +16,7 @@ class RegisterState extends Equatable {
|
|||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
final String? pendingEmail;
|
final String? pendingEmail;
|
||||||
final bool codeSent;
|
final bool codeSent;
|
||||||
|
final bool isSending;
|
||||||
|
|
||||||
const RegisterState({
|
const RegisterState({
|
||||||
this.username = const Username.pure(),
|
this.username = const Username.pure(),
|
||||||
@@ -26,6 +27,7 @@ class RegisterState extends Equatable {
|
|||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
this.pendingEmail,
|
this.pendingEmail,
|
||||||
this.codeSent = false,
|
this.codeSent = false,
|
||||||
|
this.isSending = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
bool get isStep1Valid =>
|
bool get isStep1Valid =>
|
||||||
@@ -41,6 +43,7 @@ class RegisterState extends Equatable {
|
|||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
String? pendingEmail,
|
String? pendingEmail,
|
||||||
bool? codeSent,
|
bool? codeSent,
|
||||||
|
bool? isSending,
|
||||||
}) {
|
}) {
|
||||||
return RegisterState(
|
return RegisterState(
|
||||||
username: username ?? this.username,
|
username: username ?? this.username,
|
||||||
@@ -51,6 +54,7 @@ class RegisterState extends Equatable {
|
|||||||
errorMessage: errorMessage,
|
errorMessage: errorMessage,
|
||||||
pendingEmail: pendingEmail ?? this.pendingEmail,
|
pendingEmail: pendingEmail ?? this.pendingEmail,
|
||||||
codeSent: codeSent ?? this.codeSent,
|
codeSent: codeSent ?? this.codeSent,
|
||||||
|
isSending: isSending ?? this.isSending,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +68,7 @@ class RegisterState extends Equatable {
|
|||||||
errorMessage,
|
errorMessage,
|
||||||
pendingEmail,
|
pendingEmail,
|
||||||
codeSent,
|
codeSent,
|
||||||
|
isSending,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,4 +165,31 @@ class RegisterCubit extends Cubit<RegisterState> {
|
|||||||
emit(state.copyWith(errorMessage: message));
|
emit(state.copyWith(errorMessage: message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> sendCodeSilently() async {
|
||||||
|
if (!state.isStep1Valid) return;
|
||||||
|
|
||||||
|
emit(state.copyWith(isSending: true));
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await _repository.signupStart(
|
||||||
|
SignupStartRequest(
|
||||||
|
username: state.username.value,
|
||||||
|
email: state.email.value,
|
||||||
|
password: state.password.value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
isSending: false,
|
||||||
|
pendingEmail: response.email,
|
||||||
|
codeSent: true,
|
||||||
|
errorMessage: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
final message = e is ApiException ? e.message : '验证码发送失败,请重试';
|
||||||
|
emit(state.copyWith(isSending: false, errorMessage: message));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import 'package:bloc_test/bloc_test.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:formz/formz.dart';
|
import 'package:formz/formz.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:social_app/core/form_inputs/form_inputs.dart';
|
||||||
import 'package:social_app/features/auth/data/auth_repository.dart';
|
import 'package:social_app/features/auth/data/auth_repository.dart';
|
||||||
|
import 'package:social_app/features/auth/data/models/auth_response.dart';
|
||||||
|
import 'package:social_app/features/auth/data/models/signup_request.dart';
|
||||||
import 'package:social_app/features/auth/presentation/cubits/register_cubit.dart';
|
import 'package:social_app/features/auth/presentation/cubits/register_cubit.dart';
|
||||||
|
|
||||||
class MockAuthRepository extends Mock implements AuthRepository {}
|
class MockAuthRepository extends Mock implements AuthRepository {}
|
||||||
@@ -14,6 +17,9 @@ void main() {
|
|||||||
setUp(() {
|
setUp(() {
|
||||||
mockRepository = MockAuthRepository();
|
mockRepository = MockAuthRepository();
|
||||||
cubit = RegisterCubit(mockRepository);
|
cubit = RegisterCubit(mockRepository);
|
||||||
|
registerFallbackValue(
|
||||||
|
SignupStartRequest(username: '', email: '', password: ''),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() {
|
tearDown(() {
|
||||||
@@ -46,4 +52,39 @@ void main() {
|
|||||||
expect: () => [isA<RegisterState>()],
|
expect: () => [isA<RegisterState>()],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('sendCodeSilently', () {
|
||||||
|
blocTest<RegisterCubit, RegisterState>(
|
||||||
|
'sets isSending to true then false on success',
|
||||||
|
build: () => cubit,
|
||||||
|
seed: () => RegisterState(
|
||||||
|
username: const Username.dirty('testuser'),
|
||||||
|
email: const Email.dirty('test@example.com'),
|
||||||
|
password: const Password.dirty('password123'),
|
||||||
|
),
|
||||||
|
setUp: () {
|
||||||
|
when(() => mockRepository.signupStart(any())).thenAnswer(
|
||||||
|
(_) async => SignupStartResponse(
|
||||||
|
status: 'ok',
|
||||||
|
email: 'test@example.com',
|
||||||
|
message: 'Code sent',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
act: (c) => c.sendCodeSilently(),
|
||||||
|
expect: () => [
|
||||||
|
predicate<RegisterState>((state) => state.isSending == true),
|
||||||
|
predicate<RegisterState>(
|
||||||
|
(state) =>
|
||||||
|
state.isSending == false &&
|
||||||
|
state.codeSent == true &&
|
||||||
|
state.pendingEmail == 'test@example.com' &&
|
||||||
|
state.errorMessage == null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
verify: (_) {
|
||||||
|
verify(() => mockRepository.signupStart(any())).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user