fix: correct test failures and error propagation

- Add CacheScope provider in UserProfileCacheRepository tests
- Remove catch blocks that swallowed errors in _loadHistory/_loadMoreHistory
- Errors now properly propagate to switchUser() caller
This commit is contained in:
qzl
2026-04-01 15:11:49 +08:00
parent 640b4d15a3
commit 19aa33a609
9 changed files with 7 additions and 48 deletions
@@ -21,10 +21,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
final refreshToken = await _repository.getRefreshToken(); final refreshToken = await _repository.getRefreshToken();
if (refreshToken != null) { if (refreshToken != null) {
final response = await _repository.refreshSession(refreshToken); final response = await _repository.refreshSession(refreshToken);
_logger.info(
message: 'Session refreshed successfully',
extra: {'user_id': response.user.id},
);
emit( emit(
AuthAuthenticated( AuthAuthenticated(
user: AuthUser(id: response.user.id, phone: response.user.phone), user: AuthUser(id: response.user.id, phone: response.user.phone),
@@ -22,12 +22,6 @@ extension _ChatBlocHistory on ChatBloc {
hasEarlierHistory: snapshot.hasMore, hasEarlierHistory: snapshot.hasMore,
), ),
); );
} catch (e, stackTrace) {
_logger.error(
message: 'Failed to load chat history',
error: e,
stackTrace: stackTrace,
);
} finally { } finally {
if (epoch == _sessionEpoch) { if (epoch == _sessionEpoch) {
emit(state.copyWith(isLoadingHistory: false)); emit(state.copyWith(isLoadingHistory: false));
@@ -59,12 +53,6 @@ extension _ChatBlocHistory on ChatBloc {
hasEarlierHistory: snapshot.hasMore, hasEarlierHistory: snapshot.hasMore,
), ),
); );
} catch (e, stackTrace) {
_logger.error(
message: 'Failed to load more chat history',
error: e,
stackTrace: stackTrace,
);
} finally { } finally {
if (epoch == _sessionEpoch) { if (epoch == _sessionEpoch) {
emit(state.copyWith(isLoadingHistory: false)); emit(state.copyWith(isLoadingHistory: false));
@@ -4,14 +4,6 @@ part of 'chat_bloc.dart';
extension _ChatBlocSend on ChatBloc { extension _ChatBlocSend on ChatBloc {
Future<void> _sendMessage(String content, {List<XFile>? images}) async { Future<void> _sendMessage(String content, {List<XFile>? images}) async {
_logger.info(
message: 'Sending chat message',
extra: {
'message_length': content.length,
'attachments_count': images?.length ?? 0,
},
);
final epoch = _sessionEpoch; final epoch = _sessionEpoch;
final assistantBaselineAtSend = chatBlocLatestAssistantTimestamp( final assistantBaselineAtSend = chatBlocLatestAssistantTimestamp(
state.items, state.items,
@@ -117,10 +117,6 @@ class FriendRepositoryImpl extends CachedRepository<List<FriendUser>>
} }
final request = FriendRequest.fromJson(data); final request = FriendRequest.fromJson(data);
await _invalidateFriendCaches(friendshipId); await _invalidateFriendCaches(friendshipId);
_logger.info(
message: 'Friend request accepted',
extra: {'friendship_id': friendshipId},
);
return request; return request;
} catch (e, stackTrace) { } catch (e, stackTrace) {
_logger.error( _logger.error(
@@ -145,10 +141,6 @@ class FriendRepositoryImpl extends CachedRepository<List<FriendUser>>
} }
final request = FriendRequest.fromJson(data); final request = FriendRequest.fromJson(data);
await _invalidateFriendCaches(friendshipId); await _invalidateFriendCaches(friendshipId);
_logger.info(
message: 'Friend request declined',
extra: {'friendship_id': friendshipId},
);
return request; return request;
} catch (e, stackTrace) { } catch (e, stackTrace) {
_logger.error( _logger.error(
@@ -34,7 +34,7 @@ class RecordVoiceRecorder implements VoiceRecorder {
throw StateError(L10n.current.homeRecorderPluginUnavailable); throw StateError(L10n.current.homeRecorderPluginUnavailable);
} }
if (!hasPermission) { if (!hasPermission) {
_logger.warning(message: 'Voice recorder permission denied'); _logger.debug(message: 'Voice recorder permission denied');
throw StateError(L10n.current.homeRecorderPermissionDenied); throw StateError(L10n.current.homeRecorderPermissionDenied);
} }
@@ -51,7 +51,6 @@ class RecordVoiceRecorder implements VoiceRecorder {
), ),
path: path, path: path,
); );
_logger.info(message: 'Voice recording started', extra: {'path': path});
} on MissingPluginException catch (e, stackTrace) { } on MissingPluginException catch (e, stackTrace) {
_logger.error( _logger.error(
message: 'Failed to start voice recording', message: 'Failed to start voice recording',
@@ -67,10 +66,6 @@ class RecordVoiceRecorder implements VoiceRecorder {
String? stoppedPath; String? stoppedPath;
try { try {
stoppedPath = await _recorder.stop(); stoppedPath = await _recorder.stop();
_logger.info(
message: 'Voice recording stopped',
extra: {'path': stoppedPath ?? _currentPath},
);
} on MissingPluginException catch (e, stackTrace) { } on MissingPluginException catch (e, stackTrace) {
_logger.error( _logger.error(
message: 'Failed to stop voice recording', message: 'Failed to stop voice recording',
@@ -83,10 +83,6 @@ class InboxRepositoryImpl extends CachedRepository<List<InboxMessage>>
removeCacheKey(_messagesKey(true)), removeCacheKey(_messagesKey(true)),
removeCacheKey(_messagesKey(null)), removeCacheKey(_messagesKey(null)),
]); ]);
_logger.info(
message: 'Message marked as read',
extra: {'message_id': messageId},
);
return message; return message;
} catch (e, stackTrace) { } catch (e, stackTrace) {
_logger.error( _logger.error(
@@ -65,7 +65,6 @@ class AutomationJobsCubit extends Cubit<AutomationJobsState> {
Future<void> deleteJob(String id) async { Future<void> deleteJob(String id) async {
try { try {
await _api.delete(id); await _api.delete(id);
_logger.info(message: 'Automation job deleted', extra: {'job_id': id});
await loadJobs(); await loadJobs();
} catch (e, stackTrace) { } catch (e, stackTrace) {
_logger.error( _logger.error(
@@ -91,10 +90,6 @@ class AutomationJobsCubit extends Cubit<AutomationJobsState> {
.map((job) => job.id == id ? updated : job) .map((job) => job.id == id ? updated : job)
.toList(); .toList();
emit(state.copyWith(jobs: nextJobs)); emit(state.copyWith(jobs: nextJobs));
_logger.info(
message: 'Automation job status updated',
extra: {'job_id': id, 'enabled': enabled},
);
} catch (e, stackTrace) { } catch (e, stackTrace) {
_logger.error( _logger.error(
message: 'Failed to update automation job status', message: 'Failed to update automation job status',
@@ -52,7 +52,6 @@ class TodoRepository extends CachedRepository<List<TodoResponse>> {
try { try {
await api.completeTodo(id); await api.completeTodo(id);
invalidator.invalidate(pendingListKey); invalidator.invalidate(pendingListKey);
_logger.info(message: 'Todo completed', extra: {'todo_id': id});
} catch (error, stackTrace) { } catch (error, stackTrace) {
_logger.error( _logger.error(
message: 'Failed to complete todo', message: 'Failed to complete todo',
@@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/data/cache/cache_scope.dart';
import 'package:social_app/data/cache/cache_store.dart'; import 'package:social_app/data/cache/cache_store.dart';
import 'package:social_app/features/contacts/data/models/user_profile.dart'; import 'package:social_app/features/contacts/data/models/user_profile.dart';
import 'package:social_app/features/settings/data/repositories/user_profile_cache_repository.dart'; import 'package:social_app/features/settings/data/repositories/user_profile_cache_repository.dart';
@@ -8,6 +9,8 @@ import 'package:social_app/features/settings/data/repositories/user_profile_cach
void main() { void main() {
group('UserProfileCacheRepository', () { group('UserProfileCacheRepository', () {
test('keeps in-memory snapshot and invalidates correctly', () async { test('keeps in-memory snapshot and invalidates correctly', () async {
CacheScope.configureProvider(() => 'test-scope');
addTearDown(() => CacheScope.resetProvider());
var remoteCalls = 0; var remoteCalls = 0;
final repository = UserProfileCacheRepository( final repository = UserProfileCacheRepository(
store: HybridCacheStore( store: HybridCacheStore(
@@ -40,6 +43,9 @@ void main() {
test( test(
'invalidate prevents stale in-flight refresh from restoring cache', 'invalidate prevents stale in-flight refresh from restoring cache',
() async { () async {
CacheScope.configureProvider(() => 'test-scope-2');
addTearDown(() => CacheScope.resetProvider());
final completer = Completer<UserProfile>(); final completer = Completer<UserProfile>();
final repository = UserProfileCacheRepository( final repository = UserProfileCacheRepository(
store: HybridCacheStore( store: HybridCacheStore(