Files
eatvio_app/test/features/chat/presentation/bloc/chats_cubit_test.dart
2025-12-03 18:12:17 +03:00

199 lines
8.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'package:eatvio_app/core/enums/base_state.dart';
import 'package:eatvio_app/core/models/pagination_model.dart';
import 'package:eatvio_app/core/websockets/ws_manager.dart';
import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_state.dart';
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
import 'chats_cubit_test.mocks.dart';
@GenerateNiceMocks([MockSpec<ChatRepository>(), MockSpec<ProfileRepository>(), MockSpec<WsManager>(), MockSpec<StreamSubscription>()])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('ChatsCubit', () {
late ChatsCubit chatsCubit;
late MockChatRepository mockChatRepository;
late MockProfileRepository mockProfileRepository;
late MockWsManager mockWsManager;
const testChatRoomsPagination = ChatRoomPaginationModel(
data: [],
unreadChatsCount: 0,
meta: Meta(currentPage: 1, from: null, lastPage: 1, links: [], perPage: 10, to: null, total: 0),
);
setUp(() {
mockChatRepository = MockChatRepository();
mockProfileRepository = MockProfileRepository();
mockWsManager = MockWsManager();
chatsCubit = ChatsCubit(chatRepository: mockChatRepository, wsManager: mockWsManager, profileRepository: mockProfileRepository);
});
tearDown(() async {
await Future.delayed(const Duration(milliseconds: 100));
if (!chatsCubit.isClosed) {
await chatsCubit.close();
}
});
test('начальное состояние - initial', () {
expect(chatsCubit.state, isA<ChatsState>());
expect(chatsCubit.state.state, BaseState.initial);
});
test('getChatRoomsWithLoading - загружает комнаты с loading состоянием', () async {
when(mockChatRepository.getChatRooms(query: null)).thenAnswer((_) async => testChatRoomsPagination);
await chatsCubit.getChatRoomsWithLoading();
await Future.delayed(const Duration(milliseconds: 100));
expect(chatsCubit.state.state, BaseState.success);
verify(mockChatRepository.getChatRooms(query: null)).called(1);
});
test('getChatRoomsWithLoading - обрабатывает ошибку', () async {
when(mockChatRepository.getChatRooms(query: null)).thenThrow(Exception('Network error'));
await chatsCubit.getChatRoomsWithLoading();
await Future.delayed(const Duration(milliseconds: 100));
expect(chatsCubit.state.state, BaseState.error);
expect(chatsCubit.state.errorMessage, isNotNull);
});
test('getChatRooms - загружает комнаты без loading состояния', () async {
when(mockChatRepository.getChatRooms(query: null)).thenAnswer((_) async => testChatRoomsPagination);
await chatsCubit.getChatRooms();
await Future.delayed(const Duration(milliseconds: 100));
expect(chatsCubit.state.state, BaseState.success);
verify(mockChatRepository.getChatRooms(query: null)).called(1);
});
test('getChatRooms - загружает комнаты с запросом', () async {
const query = 'test query';
when(mockChatRepository.getChatRooms(query: query)).thenAnswer((_) async => testChatRoomsPagination);
await chatsCubit.getChatRooms(query: query);
await Future.delayed(const Duration(milliseconds: 100));
expect(chatsCubit.state.state, BaseState.success);
verify(mockChatRepository.getChatRooms(query: query)).called(1);
});
test('loadMoreChatRooms - загружает больше комнат', () async {
// Create pagination with lastPage > 1 so loadMoreChatRooms doesn't return early
const paginationPage1 = ChatRoomPaginationModel(
data: [],
unreadChatsCount: 0,
meta: Meta(
currentPage: 1,
from: null,
lastPage: 3, // Set to 3 so we can load more
links: [],
perPage: 10,
to: null,
total: 30,
),
);
const paginationPage2 = ChatRoomPaginationModel(
data: [],
unreadChatsCount: 0,
meta: Meta(currentPage: 2, from: null, lastPage: 3, links: [], perPage: 10, to: null, total: 30),
);
when(mockChatRepository.getChatRooms(query: null, page: 1)).thenAnswer((_) async => paginationPage1);
// Сначала загружаем первую страницу
await chatsCubit.getChatRooms();
await Future.delayed(const Duration(milliseconds: 100));
// Затем загружаем следующую страницу
when(mockChatRepository.getChatRooms(query: null, page: 2)).thenAnswer((_) async => paginationPage2);
await chatsCubit.loadMoreChatRooms();
await Future.delayed(const Duration(milliseconds: 100));
verify(mockChatRepository.getChatRooms(query: null, page: 2)).called(1);
});
test('loadMoreChatRooms - не загружает если уже загружается', () async {
when(mockChatRepository.getChatRooms(query: null)).thenAnswer((_) async => testChatRoomsPagination);
await chatsCubit.getChatRooms();
await Future.delayed(const Duration(milliseconds: 100));
// Устанавливаем isLoadingMoreChats в true
chatsCubit.emit(chatsCubit.state.copyWith(isLoadingMoreChats: true));
await chatsCubit.loadMoreChatRooms();
// Не должно вызывать репозиторий
verifyNever(mockChatRepository.getChatRooms(query: null, page: 2));
});
test('reduceUnreadMessagesCount - уменьшает количество непрочитанных сообщений', () {
const chatId = 'chat-id';
const count = 2;
const chatRoom = ChatRoom(
id: chatId,
lastMessage: null,
users: Users(
fromChatUser: ChatUser(id: 1, name: 'User 1', profilePhotoPath: null, profilePhotoUrl: ''),
toChatUser: ChatUser(id: 2, name: 'User 2', profilePhotoPath: null, profilePhotoUrl: ''),
),
unreadMessagesCount: 5,
chosenPlan: null,
);
const pagination = ChatRoomPaginationModel(
data: [chatRoom],
unreadChatsCount: 1,
meta: Meta(currentPage: 1, from: null, lastPage: 1, links: [], perPage: 10, to: null, total: 1),
);
chatsCubit.emit(ChatsState(state: BaseState.success, chatRooms: pagination.data, chatsWithUnreadMessagesCount: 1));
chatsCubit.reduceUnreadMessagesCount(chatId: chatId, count: count);
final updatedState = chatsCubit.state;
final updatedRoom = updatedState.chatRooms.firstWhere((r) => r.id == chatId);
expect(updatedRoom.unreadMessagesCount, 3);
});
test('connectToWebSocket - подключается к WebSocket', () async {
const mockStream = Stream<ChannelReadEvent>.empty();
when(mockWsManager.newMessagesStream).thenAnswer((_) => mockStream);
await chatsCubit.connectToWebSocket();
verify(mockWsManager.newMessagesStream).called(1);
});
test('close - закрывает cubit и отписывается от подписок', () async {
final mockSubscription1 = MockStreamSubscription();
when(mockSubscription1.cancel()).thenAnswer((_) async => Future.value());
// Set newIncomingMessagesSubscription
chatsCubit.newIncomingMessagesSubscription = mockSubscription1;
await chatsCubit.close();
// Verify that cancel was called on newIncomingMessagesSubscription
verify(mockSubscription1.cancel()).called(1);
// newLastMessageSubscription is cancelled in super.close() which we can't easily verify
// but the test verifies that the method completes without error
});
});
}