Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adiciona testes para a página de chats #180

Merged
merged 4 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/app/features/chat/presentation/chat_main_module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ChatMainModule extends WidgetModule {
modulesServices: i.get<IAppModulesServices>(),
),
),
Bind.factory(
Bind.factory<IChatMainTalksController>(
(i) => ChatMainTalksController(
chatChannelRepository: i.get<IChatChannelRepository>(),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@ import '../../domain/states/chat_main_talks_state.dart';

part 'chat_main_talks_controller.g.dart';

class ChatMainTalksController extends _ChatMainTalksControllerBase
with _$ChatMainTalksController {
ChatMainTalksController({
required IChatChannelRepository chatChannelRepository,
}) : super(chatChannelRepository);
}
class ChatMainTalksController = IChatMainTalksController
with _$ChatMainTalksController;

abstract class _ChatMainTalksControllerBase with Store, MapFailureMessage {
_ChatMainTalksControllerBase(this._chatChannelRepository) {
abstract class IChatMainTalksController with Store, MapFailureMessage {
IChatMainTalksController({
required IChatChannelRepository chatChannelRepository,
}) : _chatChannelRepository = chatChannelRepository {
_init();
}

Expand Down Expand Up @@ -68,7 +66,7 @@ abstract class _ChatMainTalksControllerBase with Store, MapFailureMessage {
}
}

extension _ChatMainTalksControllerBasePrivate on _ChatMainTalksControllerBase {
extension _ChatMainTalksControllerBasePrivate on IChatMainTalksController {
Future<void> forwardToChat(ChatChannelOpenEntity session) async {
return Modular.to
.pushNamed('/mainboard/chat/${session.token}', arguments: session)
Expand Down Expand Up @@ -134,7 +132,7 @@ extension _ChatMainTalksControllerBasePrivate on _ChatMainTalksControllerBase {
tiles.add(ChatMainAssistantCardTile(cards: cards));
}

if (session.channels!.isNotEmpty) {
if (session.channels?.isEmpty == false) {
final total = session.channels!.length;
final title = total > 1 ? 'Suas conversas ($total)' : 'Sua conversa';
tiles.add(ChatMainChannelHeaderTile(title: title));
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class ChatMainTalksPage extends StatefulWidget {
}

class _ChatMainTalksPageState
extends ModularState<ChatMainTalksPage, ChatMainTalksController> {
extends ModularState<ChatMainTalksPage, IChatMainTalksController> {
@override
Widget build(BuildContext context) {
return Container(
Expand Down
12 changes: 7 additions & 5 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -991,14 +991,16 @@ packages:
name: mocktail
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "1.0.0"
mocktail_image_network:
dependency: "direct dev"
description:
name: mocktail_image_network
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1"
path: "packages/mocktail_image_network"
ref: HEAD
resolved-ref: "2fd21e9e7b4447907eb34428fbb8133c5976a90c"
url: "https://github.com/pedrox-hs/mocktail.git"
source: git
version: "1.1.0"
nested:
dependency: transitive
description:
Expand Down
8 changes: 6 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ dev_dependencies:
json_serializable: ^6.3.1
lint: ^1.8.1
mobx_codegen: ^2.0.4
mocktail: ^0.3.0
mocktail_image_network: ^0.3.1
mocktail: ^1.0.0
mocktail_image_network: ^1.1.0
plugin_platform_interface: ^2.0.0

dependency_overrides:
Expand Down Expand Up @@ -128,6 +128,10 @@ dependency_overrides:
git:
url: https://github.com/pedrox-hs/flutter_tags.git
ref: null-safety
mocktail_image_network:
git:
url: https://github.com/pedrox-hs/mocktail.git
path: packages/mocktail_image_network
smooth_star_rating:
git:
url: https://github.com/bhavin-concetto/smoothratingbar.git
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import 'package:dartz/dartz.dart' show right, left;
import 'package:flutter_modular/flutter_modular.dart';
import 'package:flutter_modular_test/flutter_modular_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:mocktail_image_network/mocktail_image_network.dart';
import 'package:penhas/app/core/error/failures.dart';
import 'package:penhas/app/features/appstate/domain/entities/app_state_entity.dart';
import 'package:penhas/app/features/chat/domain/entities/chat_assistant_entity.dart';
import 'package:penhas/app/features/chat/domain/entities/chat_channel_available_entity.dart';
import 'package:penhas/app/features/chat/domain/entities/chat_channel_entity.dart';
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/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;

setUp(() {
mockRepository = _MockChatChannelRepository();
Modular.navigatorDelegate = mockNavigator = _MockModularNavigate();

loadModules(
[ChatMainModule()],
overrides: [
Bind<IChatChannelRepository>((i) => mockRepository),
],
);

when(() => mockRepository.listChannel()).thenAnswer(
(_) async => right(_chatChannelAvailabelFixture),
);
});

screenshotTest(
'loaded state should be rendered',
fileName: 'chat_main_talks_page_initial_state',
pageBuilder: () => ChatMainTalksPage(),
);

screenshotTest(
'error state should be rendered',
fileName: 'chat_main_talks_page_error_state',
pageBuilder: () => ChatMainTalksPage(),
setUp: () {
when(() => mockRepository.listChannel()).thenAnswer(
(_) async => left(ServerFailure()),
);
},
);

testWidgets(
'should navigate to assistant quiz when open assistant card',
(tester) => mockNetworkImages(() async {
// arrange
final widget = buildTestableWidget(ChatMainTalksPage());
await tester.pumpWidget(widget);
await tester.pumpAndSettle();
when(
() => mockNavigator.popAndPushNamed(
any(),
arguments: any(named: 'arguments'),
),
).thenAnswer((_) => Future.value());

// act
await tester.tap(find.text('Assistente PenhaS'));

// assert
verify(
() => mockNavigator.popAndPushNamed(
'/quiz?origin=chat',
arguments: QuizSessionEntity(
sessionId: 'assistant-quiz-session',
),
),
).called(1);
}),
);

testWidgets(
'should navigate to support chat when open support card',
(tester) => mockNetworkImages(() async {
// arrange
final widget = buildTestableWidget(ChatMainTalksPage());
await tester.pumpWidget(widget);
await tester.pumpAndSettle();
when(
() => mockNavigator.pushNamed(
any(),
arguments: any(named: 'arguments'),
),
).thenAnswer((_) => Future.value(true));

// act
await tester.tap(find.text('Suporte PenhaS'));

// assert
// verifyZeroInteractions(mockNavigator);
verify(
() => mockNavigator.pushNamed(
'/mainboard/chat/support-channel',
arguments: ChatChannelOpenEntity(token: 'support-channel'),
),
).called(1);
}),
);

testWidgets(
'should navigate to chat page when open conversation card',
(tester) => mockNetworkImages(() async {
// arrange
final widget = buildTestableWidget(ChatMainTalksPage());
await tester.pumpWidget(widget);
await tester.pumpAndSettle();
when(
() => mockNavigator.pushNamed(
any(),
arguments: any(named: 'arguments'),
),
).thenAnswer((_) => Future.value(true));

// act
await tester.tap(find.text('Mary'));

// assert
verify(
() => mockNavigator.pushNamed(
'/mainboard/chat/talk-with-mary',
arguments: ChatChannelOpenEntity(token: 'talk-with-mary'),
),
).called(1);
}),
);
});
}

class _MockModularNavigate extends Mock implements IModularNavigator {}

class _MockChatChannelRepository extends Mock
implements IChatChannelRepository {}

final _chatChannelAvailabelFixture = ChatChannelAvailableEntity(
assistant: ChatAssistantEntity(
avatar: null,
quizSession: QuizSessionEntity(
sessionId: 'assistant-quiz-session',
),
title: 'Assistente PenhaS',
subtitle: 'Entenda como posso te ajudar',
),
support: ChatChannelEntity(
token: 'support-channel',
lastMessageIsMime: false,
lastMessageTime: DateTime.parse('2024-03-02'),
user: ChatUserEntity(
userId: null,
activity: null,
blockedMe: false,
avatar: null,
nickname: 'Suporte PenhaS',
),
),
channels: [
ChatChannelEntity(
token: 'talk-with-mary',
lastMessageIsMime: false,
lastMessageTime: DateTime.parse('2024-03-02'),
user: ChatUserEntity(
userId: null,
activity: 'Ativo',
blockedMe: false,
avatar: 'http://example.com/avatar.svg',
nickname: 'Mary',
),
),
ChatChannelEntity(
token: 'talk-with-annie',
lastMessageIsMime: false,
lastMessageTime: DateTime.parse('2024-03-02'),
user: ChatUserEntity(
userId: null,
activity: 'Há 1 minuto',
blockedMe: true,
avatar: 'http://example.com/avatar.svg',
nickname: 'Annie',
),
),
],
hasMore: false,
nextPage: null,
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions test/utils/module_testing.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:flutter_modular/src/presenters/navigation/modular_route_information_parser.dart';
import 'package:flutter_modular_test/flutter_modular_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:penhas/app/app_module.dart';

import 'aditional_bind_module.dart';

void loadModules(
List<Module> modules, {
List<Bind> overrides = const [],
}) {
modules = [
AditionalBindModule(binds: overrides),
...modules,
];
initModules(
modules,
replaceBinds: overrides,
);

addTearDown(() {
modules.forEach(Modular.removeModule);
});
}

Widget buildTestableApp({
Widget? home,
String? initialRoute,
Expand Down
Loading