diff --git a/lib/app/features/chat/presentation/chat_main_module.dart b/lib/app/features/chat/presentation/chat_main_module.dart index 57f11dd5f..5c31078a6 100644 --- a/lib/app/features/chat/presentation/chat_main_module.dart +++ b/lib/app/features/chat/presentation/chat_main_module.dart @@ -27,7 +27,7 @@ class ChatMainModule extends WidgetModule { modulesServices: i.get(), ), ), - Bind.factory( + Bind.factory( (i) => ChatMainTalksController( chatChannelRepository: i.get(), ), @@ -52,7 +52,13 @@ class ChatMainModule extends WidgetModule { @override Widget get view => ChatMainPage( - chatMainPeopleController: Modular.get(), - controller: Modular.get(), + chatMainPeopleController: ChatMainPeopleController( + skillRepository: Modular.get(), + usersRepository: Modular.get()), + controller: ChatMainController( + chatToggleFeature: ChatPrivateToggleFeature( + modulesServices: Modular.get())), + chatMainTalksController: ChatMainTalksController( + chatChannelRepository: Modular.get()), ); } diff --git a/lib/app/features/chat/presentation/chat_main_page.dart b/lib/app/features/chat/presentation/chat_main_page.dart index ed36ff84c..ec4feefff 100644 --- a/lib/app/features/chat/presentation/chat_main_page.dart +++ b/lib/app/features/chat/presentation/chat_main_page.dart @@ -6,17 +6,20 @@ import '../domain/entities/chat_tab_item.dart'; import 'chat_main_controller.dart'; import 'people/chat_main_people_controller.dart'; import 'people/chat_main_people_page.dart'; +import 'talk/chat_main_talks_controller.dart'; import 'talk/chat_main_talks_page.dart'; class ChatMainPage extends StatefulWidget { const ChatMainPage( {Key? key, required this.chatMainPeopleController, - required this.controller}) + required this.controller, + required this.chatMainTalksController}) : super(key: key); final ChatMainPeopleController chatMainPeopleController; final ChatMainController controller; + final ChatMainTalksController chatMainTalksController; @override _ChatMainPageState createState() => _ChatMainPageState(); @@ -26,6 +29,9 @@ class _ChatMainPageState extends State { ChatMainController get controller => widget.controller; ChatMainPeopleController get chatMainPeopleController => widget.chatMainPeopleController; + ChatMainTalksController get chatMainTalksController => + widget.chatMainTalksController; + @override Widget build(BuildContext context) { return Observer( @@ -41,10 +47,12 @@ class _ChatMainPageState extends State { extension _ChatMainBuilder on _ChatMainPageState { Widget buildSupportChat() { - return const SafeArea( + return SafeArea( child: SizedBox.expand( child: Scaffold( - body: ChatMainTalksPage(), + body: ChatMainTalksPage( + controller: chatMainTalksController, + ), ), ), ); @@ -88,7 +96,9 @@ extension _ChatMainPageStatePrivate on _ChatMainPageState { ? ChatMainPeoplePage( controller: chatMainPeopleController, ) - : const ChatMainTalksPage(), + : ChatMainTalksPage( + controller: chatMainTalksController, + ), ); return TabBarView(children: widgets.toList()); } diff --git a/lib/app/features/chat/presentation/talk/chat_main_talks_controller.dart b/lib/app/features/chat/presentation/talk/chat_main_talks_controller.dart index f15ddcccb..2da133ac8 100644 --- a/lib/app/features/chat/presentation/talk/chat_main_talks_controller.dart +++ b/lib/app/features/chat/presentation/talk/chat_main_talks_controller.dart @@ -20,13 +20,11 @@ class ChatMainTalksController = IChatMainTalksController abstract class IChatMainTalksController with Store, MapFailureMessage { IChatMainTalksController({ required IChatChannelRepository chatChannelRepository, - }) : _chatChannelRepository = chatChannelRepository { - _init(); - } + }) : _chatChannelRepository = chatChannelRepository; final IChatChannelRepository _chatChannelRepository; - Future _init() async { + Future initialize() async { await loadScreen(); } diff --git a/lib/app/features/chat/presentation/talk/chat_main_talks_page.dart b/lib/app/features/chat/presentation/talk/chat_main_talks_page.dart index 7b1c3fef1..1c2f6e30b 100644 --- a/lib/app/features/chat/presentation/talk/chat_main_talks_page.dart +++ b/lib/app/features/chat/presentation/talk/chat_main_talks_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:flutter_modular/flutter_modular.dart'; import '../../../../shared/design_system/colors.dart'; import '../../../authentication/presentation/shared/page_progress_indicator.dart'; @@ -12,14 +11,24 @@ import '../pages/chat_channel_card.dart'; import 'chat_main_talks_controller.dart'; class ChatMainTalksPage extends StatefulWidget { - const ChatMainTalksPage({Key? key}) : super(key: key); + const ChatMainTalksPage({Key? key, required this.controller}) + : super(key: key); + + final ChatMainTalksController controller; @override _ChatMainTalksPageState createState() => _ChatMainTalksPageState(); } -class _ChatMainTalksPageState - extends ModularState { +class _ChatMainTalksPageState extends State { + ChatMainTalksController get controller => widget.controller; + + @override + void initState() { + super.initState(); + controller.initialize(); + } + @override Widget build(BuildContext context) { return Container( diff --git a/lib/app/features/support_center/presentation/support_center_module.dart b/lib/app/features/support_center/presentation/support_center_module.dart index 4e39eed58..7d4af1405 100644 --- a/lib/app/features/support_center/presentation/support_center_module.dart +++ b/lib/app/features/support_center/presentation/support_center_module.dart @@ -50,6 +50,10 @@ class SupportCenterModule extends WidgetModule { @override Widget get view => SupportCenterPage( - controller: Modular.get(), + controller: SupportCenterController( + supportCenterUseCase: SupportCenterUseCase( + locationService: Modular.get(), + supportCenterRepository: SupportCenterRepository( + apiProvider: Modular.get()))), ); } diff --git a/test/app/features/chat/presentation/talk/chat_main_talks_page_test.dart b/test/app/features/chat/presentation/talk/chat_main_talks_page_test.dart index 4b901987b..b7851d8c8 100644 --- a/test/app/features/chat/presentation/talk/chat_main_talks_page_test.dart +++ b/test/app/features/chat/presentation/talk/chat_main_talks_page_test.dart @@ -1,4 +1,5 @@ import 'package:dartz/dartz.dart' show right, left; +import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular_test/flutter_modular_test.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -12,27 +13,23 @@ import 'package:penhas/app/features/chat/domain/entities/chat_channel_entity.dar import 'package:penhas/app/features/chat/domain/entities/chat_channel_open_entity.dart'; import 'package:penhas/app/features/chat/domain/entities/chat_user_entity.dart'; import 'package:penhas/app/features/chat/domain/repositories/chat_channel_repository.dart'; -import 'package:penhas/app/features/chat/presentation/chat_main_module.dart'; +import 'package:penhas/app/features/chat/presentation/pages/chat_assistant_card.dart'; +import 'package:penhas/app/features/chat/presentation/pages/chat_channel_card.dart'; +import 'package:penhas/app/features/chat/presentation/talk/chat_main_talks_controller.dart'; import 'package:penhas/app/features/chat/presentation/talk/chat_main_talks_page.dart'; import '../../../../../utils/golden_tests.dart'; -import '../../../../../utils/module_testing.dart'; void main() { group(ChatMainTalksPage, () { late IChatChannelRepository mockRepository; late IModularNavigator mockNavigator; - + late ChatMainTalksController controller; setUp(() { mockRepository = _MockChatChannelRepository(); Modular.navigatorDelegate = mockNavigator = _MockModularNavigate(); - - loadModules( - [ChatMainModule()], - overrides: [ - Bind((i) => mockRepository), - ], - ); + controller = + ChatMainTalksController(chatChannelRepository: mockRepository); when(() => mockRepository.listChannel()).thenAnswer( (_) async => right(_chatChannelAvailableFixture), @@ -42,13 +39,17 @@ void main() { screenshotTest( 'loaded state should be rendered', fileName: 'chat_main_talks_page_initial_state', - pageBuilder: () => ChatMainTalksPage(), + pageBuilder: () => ChatMainTalksPage( + controller: controller, + ), ); screenshotTest( 'error state should be rendered', fileName: 'chat_main_talks_page_error_state', - pageBuilder: () => ChatMainTalksPage(), + pageBuilder: () => ChatMainTalksPage( + controller: controller, + ), setUp: () { when(() => mockRepository.listChannel()).thenAnswer( (_) async => left(ServerFailure()), @@ -60,7 +61,9 @@ void main() { 'should navigate to assistant quiz when open assistant card', (tester) => mockNetworkImages(() async { // arrange - final widget = buildTestableWidget(ChatMainTalksPage()); + final widget = buildTestableWidget(ChatMainTalksPage( + controller: controller, + )); await tester.pumpWidget(widget); await tester.pumpAndSettle(); when( @@ -89,7 +92,9 @@ void main() { 'should navigate to support chat when open support card', (tester) => mockNetworkImages(() async { // arrange - final widget = buildTestableWidget(ChatMainTalksPage()); + final widget = buildTestableWidget(ChatMainTalksPage( + controller: controller, + )); await tester.pumpWidget(widget); await tester.pumpAndSettle(); when( @@ -117,7 +122,9 @@ void main() { 'should navigate to chat page when open conversation card', (tester) => mockNetworkImages(() async { // arrange - final widget = buildTestableWidget(ChatMainTalksPage()); + final widget = buildTestableWidget(ChatMainTalksPage( + controller: controller, + )); await tester.pumpWidget(widget); await tester.pumpAndSettle(); when( @@ -139,6 +146,86 @@ void main() { ).called(1); }), ); + + testWidgets( + 'should display loading state', + (tester) => mockNetworkImages(() async { + // arrange + when(() => mockRepository.listChannel()).thenAnswer( + (_) async => right(_chatChannelAvailableFixture), + ); + // act + await tester.pumpWidget( + MaterialApp( + home: ChatMainTalksPage(controller: controller), + ), + ); + await tester.pumpAndSettle(); + + // Assert + expect(find.byType(ChatChannelCard), findsNWidgets(2)); + expect(find.byType(ChatAssistantCard), findsNWidgets(2)); + expect(find.text('Suas conversas (2)'), findsOneWidget); + }), + ); + + testWidgets( + 'should trigger refresh and fetch new data when pull to refresh is activated', + (tester) => mockNetworkImages(() async { + // arrange + when(() => mockRepository.listChannel()).thenAnswer( + (_) async => right(_chatChannelAvailableFixture), + ); + // act + await tester.pumpWidget( + MaterialApp( + home: ChatMainTalksPage(controller: controller), + ), + ); + await tester.pumpAndSettle(); + + // Primeira chamada durante initialize + verify(() => mockRepository.listChannel()).called(1); + + await tester.drag(find.byType(ListView), const Offset(0, 300)); + await tester.pumpAndSettle(); + + // Assert + // Segunda chamada durante o refresh + verify(() => mockRepository.listChannel()).called(1); + }), + ); + + testWidgets( + 'should navigate to chat when assistant card is tapped', + (tester) => mockNetworkImages(() async { + // arrange + when(() => mockRepository.listChannel()).thenAnswer( + (_) async => right(_chatChannelAvailableFixture), + ); + + when(() => mockNavigator.popAndPushNamed(any(), + arguments: any(named: 'arguments'))) + .thenAnswer((_) => Future.value()); + + await tester.pumpWidget( + MaterialApp( + home: ChatMainTalksPage(controller: controller), + ), + ); + await tester.pumpAndSettle(); + // act + await tester.tap(find.text('Assistente PenhaS')); + await tester.pumpAndSettle(); + // assert + verify( + () => mockNavigator.popAndPushNamed( + '/quiz?origin=chat', + arguments: any(named: 'arguments'), + ), + ).called(1); + }), + ); }); }