forked from eatvio/eatvio_app
Merge pull request 'открытие чата из консультации' (#1110) from alex_chevski/eatvio_app:fix/1106-consultation-chat into main
Reviewed-on: eatvio/eatvio_app#1110 Reviewed-by: misha <misha@noreply.localhost>
This commit is contained in:
@@ -277,7 +277,7 @@ class CubitRegistrations {
|
||||
),
|
||||
);
|
||||
sl.registerFactory<ConsultationsCubit>(
|
||||
() => ConsultationsCubit(consultationsRepository: sl()),
|
||||
() => ConsultationsCubit(consultationsRepository: sl(), chatRepository: sl()),
|
||||
);
|
||||
sl.registerFactory<ConsultantCommentsCubit>(
|
||||
() => ConsultantCommentsCubit(diaryRepository: sl()),
|
||||
|
||||
@@ -135,9 +135,9 @@ class _EmptyChatScreenState extends State<EmptyChatScreen> {
|
||||
textEditingController.clear();
|
||||
});
|
||||
}
|
||||
final chatIdOrError = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (context.mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatIdOrError});
|
||||
final chatId = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (chatId != null && chatId.isNotEmpty && context.mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatId});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -189,9 +189,9 @@ class _EmptyChatScreenState extends State<EmptyChatScreen> {
|
||||
if (images.isNotEmpty) {
|
||||
List<File> files = images.map((image) => File(image.path)).toList();
|
||||
await sl<ChatRepository>().sendMessage(files: files, slug: widget.user.slug);
|
||||
final chatIdOrError = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatIdOrError});
|
||||
final chatId = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (chatId != null && chatId.isNotEmpty && mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatId});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -205,9 +205,9 @@ class _EmptyChatScreenState extends State<EmptyChatScreen> {
|
||||
if (images.isNotEmpty) {
|
||||
List<File> files = images.map((image) => File(image.path)).toList();
|
||||
await sl<ChatRepository>().sendMessage(files: files, slug: widget.user.slug);
|
||||
final chatIdOrError = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatIdOrError});
|
||||
final chatId = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (chatId != null && chatId.isNotEmpty && mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatId});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -243,9 +243,9 @@ class _EmptyChatScreenState extends State<EmptyChatScreen> {
|
||||
if (result != null) {
|
||||
List<File> files = result.paths.map((path) => File(path!)).toList();
|
||||
await sl<ChatRepository>().sendMessage(files: files, slug: widget.user.slug);
|
||||
final chatIdOrError = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatIdOrError});
|
||||
final chatId = await sl<ChatRepository>().getChatByUserSlug(widget.user.slug);
|
||||
if (chatId != null && chatId.isNotEmpty && mounted) {
|
||||
AppRouter.navigatorKey.currentContext?.pushReplacementNamed('chatScreen', extra: {'uuid': chatId});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -137,11 +137,12 @@ class ChatRepository {
|
||||
|
||||
}
|
||||
|
||||
Future<String> getChatByUserSlug(String slug) async {
|
||||
Future<String?> getChatByUserSlug(String slug) async {
|
||||
final response = await chatService.getChatByUserSlug(slug: slug);
|
||||
if (response.response.statusCode == 404) {
|
||||
return '404';
|
||||
final data = response.data;
|
||||
if (data is Map && data['id'] is String && (data['id'] as String).isNotEmpty) {
|
||||
return data['id'] as String;
|
||||
}
|
||||
return response.data['id'];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ part 'consultation_model.g.dart';
|
||||
abstract class ConsultationModel with _$ConsultationModel {
|
||||
factory ConsultationModel({
|
||||
required int id,
|
||||
@JsonKey(name: 'chat_id') String? chatId,
|
||||
@JsonKey(name: 'last_state') required ChosenPlanStateEnum chosenPlanState,
|
||||
@JsonKey(name: 'plan_title') required String planTitle,
|
||||
@JsonKey(name: 'user_name') required String userName,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/core/enums/base_state.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_state.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -8,7 +9,8 @@ import 'package:eatvio_app/core/error_reporting/report_from.dart';
|
||||
|
||||
class ConsultationsCubit extends Cubit<ConsultationsState> {
|
||||
final ConsultationsRepository consultationsRepository;
|
||||
ConsultationsCubit({required this.consultationsRepository}) : super(ConsultationsState());
|
||||
final ChatRepository chatRepository;
|
||||
ConsultationsCubit({required this.consultationsRepository, required this.chatRepository}) : super(ConsultationsState());
|
||||
|
||||
Future<void> loadConsultations() async {
|
||||
try {
|
||||
@@ -20,4 +22,14 @@ class ConsultationsCubit extends Cubit<ConsultationsState> {
|
||||
emit(state.copyWith(state: BaseState.error));
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> getChatIdByUserSlug(String slug) async {
|
||||
try {
|
||||
return await chatRepository.getChatByUserSlug(slug);
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
log(e.toString(), stackTrace: st);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/user_details_screen.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class ConsultationCardWidget extends StatefulWidget {
|
||||
@@ -34,6 +37,7 @@ class _ConsultationCardWidgetState extends State<ConsultationCardWidget> {
|
||||
final List<Color> legendColors = const [Colors.white, Color(0xFFF0C497), Color(0xFFFF9500), Color(0xFF2F80ED), Color(0xFF4CD964)];
|
||||
|
||||
late final List<(int, DiaryModel)> givenDaysWithDayNumber;
|
||||
bool _isOpeningChat = false;
|
||||
final List<List<DiaryStateEnum>> legendStates = [
|
||||
[DiaryStateEnum.init],
|
||||
[DiaryStateEnum.started, DiaryStateEnum.lastDayStarted],
|
||||
@@ -279,7 +283,7 @@ class _ConsultationCardWidgetState extends State<ConsultationCardWidget> {
|
||||
const SizedBox(width: 8),
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: () {},
|
||||
onTap: _isOpeningChat ? null : _openChat,
|
||||
child: Ink(
|
||||
height: 52,
|
||||
width: 52,
|
||||
@@ -308,6 +312,22 @@ class _ConsultationCardWidgetState extends State<ConsultationCardWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openChat() async {
|
||||
if (_isOpeningChat) return;
|
||||
setState(() => _isOpeningChat = true);
|
||||
var chatId = widget.consultationsModel.chatId;
|
||||
if (chatId == null || chatId.isEmpty) {
|
||||
chatId = await context.read<ConsultationsCubit>().getChatIdByUserSlug(widget.consultationsModel.userSlug);
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() => _isOpeningChat = false);
|
||||
if (chatId == null || chatId.isEmpty) {
|
||||
showErrorToast(S.of(context).msg_something_went_wrong);
|
||||
return;
|
||||
}
|
||||
GoRouter.of(context).pushNamed('chatScreen', extra: {'uuid': chatId});
|
||||
}
|
||||
|
||||
Row _legendTitle(String text, Color color) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
@@ -145,13 +145,13 @@ class ProfileCubit extends Cubit<ProfileState> {
|
||||
|
||||
Future<String?> getChatRoomIdBySlug({required String slug}) async {
|
||||
try {
|
||||
final chatIdOrError = await chatRepository.getChatByUserSlug(slug);
|
||||
final userProfile = await profileRepository.getProfileBySlug(slug);
|
||||
if (chatIdOrError == '404') {
|
||||
final chatId = await chatRepository.getChatByUserSlug(slug);
|
||||
if (chatId == null || chatId.isEmpty) {
|
||||
final userProfile = await profileRepository.getProfileBySlug(slug);
|
||||
AppRouter.navigatorKey.currentContext?.pushNamed('emptyChatScreen', extra: userProfile);
|
||||
} else {
|
||||
AppRouter.navigatorKey.currentContext?.pushNamed('chatScreen', extra: {'uuid': chatIdOrError});
|
||||
return chatIdOrError;
|
||||
AppRouter.navigatorKey.currentContext?.pushNamed('chatScreen', extra: {'uuid': chatId});
|
||||
return chatId;
|
||||
}
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
|
||||
@@ -526,11 +526,11 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test('getChatByUserSlug - возвращает 404 при отсутствии чата', () async {
|
||||
test('getChatByUserSlug - возвращает null, если в ответе нет id', () async {
|
||||
const slug = 'user-slug';
|
||||
final response = HttpResponse(
|
||||
{},
|
||||
Response(requestOptions: RequestOptions(path: ''), statusCode: 404),
|
||||
Response(requestOptions: RequestOptions(path: ''), statusCode: 200),
|
||||
);
|
||||
|
||||
when(
|
||||
@@ -539,7 +539,7 @@ void main() {
|
||||
|
||||
final result = await chatRepository.getChatByUserSlug(slug);
|
||||
|
||||
expect(result, '404');
|
||||
expect(result, isNull);
|
||||
verify(mockChatService.getChatByUserSlug(slug: slug)).called(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -156,6 +156,55 @@ void main() {
|
||||
});
|
||||
|
||||
group('ConsultationModel', () {
|
||||
test('fromJson parses chat_id', () {
|
||||
final json = {
|
||||
'id': 1,
|
||||
'chat_id': 'direct-chat-uuid',
|
||||
'last_state': 'started',
|
||||
'plan_title': 'Test Plan',
|
||||
'user_name': 'User 1',
|
||||
'user_slug': 'user-1',
|
||||
'consultant_payment': 1000.0,
|
||||
'duration': 30,
|
||||
'current_diary_day': 5,
|
||||
'user_profile_photo_url': 'photo.jpg',
|
||||
'consultation_option_price': 2000,
|
||||
'start_date': '2024-01-01T00:00:00Z',
|
||||
'end_date': '2024-01-31T00:00:00Z',
|
||||
'consultant_id': 1,
|
||||
'diaries': [],
|
||||
'personal_diet_id': null,
|
||||
};
|
||||
|
||||
final model = ConsultationModel.fromJson(json);
|
||||
|
||||
expect(model.chatId, 'direct-chat-uuid');
|
||||
});
|
||||
|
||||
test('fromJson allows missing chat_id', () {
|
||||
final json = {
|
||||
'id': 1,
|
||||
'last_state': 'started',
|
||||
'plan_title': 'Test Plan',
|
||||
'user_name': 'User 1',
|
||||
'user_slug': 'user-1',
|
||||
'consultant_payment': 1000.0,
|
||||
'duration': 30,
|
||||
'current_diary_day': 5,
|
||||
'user_profile_photo_url': 'photo.jpg',
|
||||
'consultation_option_price': 2000,
|
||||
'start_date': '2024-01-01T00:00:00Z',
|
||||
'end_date': '2024-01-31T00:00:00Z',
|
||||
'consultant_id': 1,
|
||||
'diaries': [],
|
||||
'personal_diet_id': null,
|
||||
};
|
||||
|
||||
final model = ConsultationModel.fromJson(json);
|
||||
|
||||
expect(model.chatId, isNull);
|
||||
});
|
||||
|
||||
test('toJson serializes ConsultationModel correctly', () {
|
||||
final model = ConsultationModel(
|
||||
id: 1,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:eatvio_app/core/enums/base_state.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_state.dart';
|
||||
@@ -8,14 +9,21 @@ import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockConsultationsRepository extends Mock implements ConsultationsRepository {}
|
||||
|
||||
class MockChatRepository extends Mock implements ChatRepository {}
|
||||
|
||||
void main() {
|
||||
group('ConsultationsCubit', () {
|
||||
late ConsultationsCubit cubit;
|
||||
late MockConsultationsRepository mockRepository;
|
||||
late MockChatRepository mockChatRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockConsultationsRepository();
|
||||
cubit = ConsultationsCubit(consultationsRepository: mockRepository);
|
||||
mockChatRepository = MockChatRepository();
|
||||
cubit = ConsultationsCubit(
|
||||
consultationsRepository: mockRepository,
|
||||
chatRepository: mockChatRepository,
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
@@ -47,5 +55,33 @@ void main() {
|
||||
|
||||
expect(cubit.state.state, BaseState.error);
|
||||
});
|
||||
|
||||
test('getChatIdByUserSlug - возвращает id чата', () async {
|
||||
when(() => mockChatRepository.getChatByUserSlug('john-doe'))
|
||||
.thenAnswer((_) async => 'chat-uuid');
|
||||
|
||||
final chatId = await cubit.getChatIdByUserSlug('john-doe');
|
||||
|
||||
expect(chatId, 'chat-uuid');
|
||||
verify(() => mockChatRepository.getChatByUserSlug('john-doe')).called(1);
|
||||
});
|
||||
|
||||
test('getChatIdByUserSlug - возвращает null при ошибке', () async {
|
||||
when(() => mockChatRepository.getChatByUserSlug(any()))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
final chatId = await cubit.getChatIdByUserSlug('john-doe');
|
||||
|
||||
expect(chatId, isNull);
|
||||
});
|
||||
|
||||
test('getChatIdByUserSlug - возвращает null когда чата нет', () async {
|
||||
when(() => mockChatRepository.getChatByUserSlug(any()))
|
||||
.thenAnswer((_) async => null);
|
||||
|
||||
final chatId = await cubit.getChatIdByUserSlug('john-doe');
|
||||
|
||||
expect(chatId, isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:eatvio_app/core/app_config.dart';
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/widgets/consultation_card_widget.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
class MockConsultationsCubit extends Mock implements ConsultationsCubit {}
|
||||
|
||||
void main() {
|
||||
group('ConsultationCardWidget smoke', () {
|
||||
setUpAll(() async {
|
||||
@@ -28,6 +36,20 @@ void main() {
|
||||
AppConfig(buildType: AppBuildType.tests)
|
||||
..setBaseUrl('http://localhost'),
|
||||
);
|
||||
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(
|
||||
const MethodChannel('PonnamKarthik/fluttertoast'),
|
||||
(MethodCall methodCall) async => null,
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(
|
||||
const MethodChannel('PonnamKarthik/fluttertoast'),
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
final mockConsultation = ConsultationModel(
|
||||
@@ -64,7 +86,8 @@ void main() {
|
||||
personalDietId: null,
|
||||
);
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
Widget wrap(Widget child, {ConsultationsCubit? cubit}) {
|
||||
final consultationsCubit = cubit ?? MockConsultationsCubit();
|
||||
return MaterialApp.router(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
@@ -77,7 +100,20 @@ void main() {
|
||||
routerConfig: GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: [
|
||||
GoRoute(path: '/', builder: (context, state) => child),
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => BlocProvider<ConsultationsCubit>.value(
|
||||
value: consultationsCubit,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chat-screen',
|
||||
name: 'chatScreen',
|
||||
builder: (context, state) => Scaffold(
|
||||
body: Text('chat:${(state.extra as Map)['uuid']}'),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/profile-screen',
|
||||
name: 'profileScreen',
|
||||
@@ -163,5 +199,118 @@ void main() {
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('opens chat with consultation user when chat icon tapped', (
|
||||
tester,
|
||||
) async {
|
||||
final cubit = MockConsultationsCubit();
|
||||
when(() => cubit.stream).thenAnswer((_) => const Stream.empty());
|
||||
when(() => cubit.getChatIdByUserSlug('john-doe'))
|
||||
.thenAnswer((_) async => 'chat-uuid');
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
ConsultationCardWidget(consultationsModel: mockConsultation),
|
||||
cubit: cubit,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byIcon(Icons.chat_outlined));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('chat:chat-uuid'), findsOneWidget);
|
||||
verify(() => cubit.getChatIdByUserSlug('john-doe')).called(1);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'opens chat directly with chat id without requesting it again',
|
||||
(tester) async {
|
||||
final cubit = MockConsultationsCubit();
|
||||
when(() => cubit.stream).thenAnswer((_) => const Stream.empty());
|
||||
final consultationWithChatId = mockConsultation.copyWith(
|
||||
chatId: 'direct-chat-uuid',
|
||||
);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
ConsultationCardWidget(
|
||||
consultationsModel: consultationWithChatId,
|
||||
),
|
||||
cubit: cubit,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byIcon(Icons.chat_outlined));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('chat:direct-chat-uuid'), findsOneWidget);
|
||||
verifyNever(() => cubit.getChatIdByUserSlug(any()));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('shows error and stays on card when chat id is null', (
|
||||
tester,
|
||||
) async {
|
||||
final cubit = MockConsultationsCubit();
|
||||
when(() => cubit.stream).thenAnswer((_) => const Stream.empty());
|
||||
when(() => cubit.getChatIdByUserSlug('john-doe'))
|
||||
.thenAnswer((_) async => null);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
ConsultationCardWidget(consultationsModel: mockConsultation),
|
||||
cubit: cubit,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byIcon(Icons.chat_outlined));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.pump(const Duration(seconds: 3));
|
||||
|
||||
expect(find.textContaining('chat:'), findsNothing);
|
||||
expect(
|
||||
find.byType(ConsultationCardWidget),
|
||||
findsOneWidget,
|
||||
);
|
||||
verify(() => cubit.getChatIdByUserSlug('john-doe')).called(1);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('does not request chat id twice while first is pending', (
|
||||
tester,
|
||||
) async {
|
||||
final cubit = MockConsultationsCubit();
|
||||
when(() => cubit.stream).thenAnswer((_) => const Stream.empty());
|
||||
final completer = Completer<String?>();
|
||||
when(() => cubit.getChatIdByUserSlug('john-doe'))
|
||||
.thenAnswer((_) => completer.future);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
ConsultationCardWidget(consultationsModel: mockConsultation),
|
||||
cubit: cubit,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byIcon(Icons.chat_outlined));
|
||||
await tester.tap(find.byIcon(Icons.chat_outlined));
|
||||
|
||||
completer.complete('chat-uuid');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('chat:chat-uuid'), findsOneWidget);
|
||||
verify(() => cubit.getChatIdByUserSlug('john-doe')).called(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
2
test/fixtures/doubles/profile_doubles.dart
vendored
2
test/fixtures/doubles/profile_doubles.dart
vendored
@@ -69,7 +69,7 @@ class FixtureChatRepository extends ChatRepository {
|
||||
: super(chatService: _NoopChatService());
|
||||
|
||||
@override
|
||||
Future<String> getChatByUserSlug(String slug) async {
|
||||
Future<String?> getChatByUserSlug(String slug) async {
|
||||
return 'chat-uuid-123';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user