From 1436092a35e3345fefce73596428e2b7e5875d2f Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Tue, 22 Aug 2023 07:33:54 +0200 Subject: [PATCH] Implement ChatViewModel with tests and mock data This commit introduces the ChatViewModel, which manages the business logic for chat interactions associated with tasks. The ViewModel communicates with a mock data source, offering functionalities like fetching chats for a specific task and sending chat messages. In addition to the implementation, comprehensive tests for ChatViewModel have been provided to ensure its behavior is consistent with our design goals and expectations. Key Features: Chat management in ChatViewModel. Tests covering all major functionalities of ChatViewModel. Mock data source updates to emulate chat data interactions. --- lib/viewmodels/chat_viewmodel.dart | 46 ++++++++++++++++++++++++++++ lib/viewmodels/mock_data.dart | 21 +++++++++++++ test/chat_viewmodel_test.dart | 48 ++++++++++++++++++++++++++++++ test/task_viewmodel_test.dart | 7 ++--- 4 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 test/chat_viewmodel_test.dart diff --git a/lib/viewmodels/chat_viewmodel.dart b/lib/viewmodels/chat_viewmodel.dart index e69de29b..a2b32103 100644 --- a/lib/viewmodels/chat_viewmodel.dart +++ b/lib/viewmodels/chat_viewmodel.dart @@ -0,0 +1,46 @@ +import 'package:auto_gpt_flutter_client/models/chat.dart'; +import 'package:auto_gpt_flutter_client/models/message_type.dart'; +import 'package:flutter/foundation.dart'; +import 'mock_data.dart'; // Import the mock data + +// TODO: Update whole class once we have created TaskService +class ChatViewModel with ChangeNotifier { + List _chats = []; + + /// Returns the current list of chats. + List get chats => _chats; + + /// Fetches chats from the mock data source for a specific task. + void fetchChatsForTask(int taskId) { + try { + _chats = mockChats.where((chat) => chat.taskId == taskId).toList(); + notifyListeners(); // Notify listeners to rebuild UI + print("Chats fetched successfully for task ID: $taskId"); + } catch (error) { + print("Error fetching chats: $error"); + // TODO: Handle additional error scenarios or log them as required + } + } + + /// Simulates sending a chat message for a specific task. + void sendChatMessage(int taskId, String message) { + final userChat = Chat( + id: _chats.length + 1, + taskId: taskId, + message: message, + timestamp: DateTime.now(), + messageType: MessageType.user); + + // For now, we'll simulate an agent's reply after the user's message + final agentChat = Chat( + id: _chats.length + 2, + taskId: taskId, + message: 'Automated reply to: $message', + timestamp: DateTime.now().add(const Duration(seconds: 2)), + messageType: MessageType.agent); + + _chats.addAll([userChat, agentChat]); + notifyListeners(); // Notify UI of the new chats + print("User chat and automated agent reply added for task ID: $taskId"); + } +} diff --git a/lib/viewmodels/mock_data.dart b/lib/viewmodels/mock_data.dart index 7f553d78..dab7a7cc 100644 --- a/lib/viewmodels/mock_data.dart +++ b/lib/viewmodels/mock_data.dart @@ -1,3 +1,5 @@ +import 'package:auto_gpt_flutter_client/models/chat.dart'; +import 'package:auto_gpt_flutter_client/models/message_type.dart'; import 'package:auto_gpt_flutter_client/models/task.dart'; /// A list of mock tasks for the application. @@ -18,3 +20,22 @@ void addTask(Task task) { void removeTask(int id) { mockTasks.removeWhere((task) => task.id == id); } + +// mock_data.dart (extend the existing mock_data.dart file) + +// Sample chats for mock data +List mockChats = [ + Chat( + id: 1, + taskId: 1, + message: 'Hello Agent', + timestamp: DateTime.now(), + messageType: MessageType.user), + Chat( + id: 2, + taskId: 1, + message: 'Hello! How can I assist you today?', + timestamp: DateTime.now().add(Duration(minutes: 1)), + messageType: MessageType.agent), + // ... add more mock chat data as required +]; diff --git a/test/chat_viewmodel_test.dart b/test/chat_viewmodel_test.dart new file mode 100644 index 00000000..4fa8f5c6 --- /dev/null +++ b/test/chat_viewmodel_test.dart @@ -0,0 +1,48 @@ +import 'package:auto_gpt_flutter_client/models/chat.dart'; +import 'package:auto_gpt_flutter_client/models/message_type.dart'; +import 'package:auto_gpt_flutter_client/viewmodels/chat_viewmodel.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + // Initialize the ChatViewModel + // TODO: Dependency injection in view models for testing purposes when we implement services + final viewModel = ChatViewModel(); + + group('ChatViewModel', () { + test('fetch chats for a specific task', () { + viewModel + .fetchChatsForTask(1); // Assuming task with ID 1 exists in mock data + expect(viewModel.chats.isNotEmpty, true); + expect(viewModel.chats.every((chat) => chat.taskId == 1), true); + }); + + test('send chat message for a specific task', () { + final initialChatsLength = viewModel.chats.length; + viewModel.sendChatMessage(1, 'Test message'); + expect(viewModel.chats.length, + initialChatsLength + 2); // One user message and one agent reply + expect(viewModel.chats.last.messageType, + MessageType.agent); // Last message should be agent's reply + }); + + // TODO: Refactor to return errors when we implement service + test('fetch chats for invalid task id', () { + viewModel.fetchChatsForTask( + 9999); // Assuming task with ID 9999 does not exist in mock data + expect( + viewModel.chats.where((chat) => chat.taskId == 9999).isEmpty, true); + }); + + // TODO: Refactor to return errors when we implement service + test('send chat message for invalid task id', () { + final initialChatsLength = viewModel.chats.length; + viewModel.sendChatMessage(9999, 'Invalid test message'); + expect( + viewModel.chats.length, + initialChatsLength + + 2); // Even for invalid tasks, we're currently adding mock replies + expect(viewModel.chats.last.messageType, + MessageType.agent); // Last message should be agent's reply + }); + }); +} diff --git a/test/task_viewmodel_test.dart b/test/task_viewmodel_test.dart index 13828574..a89e368d 100644 --- a/test/task_viewmodel_test.dart +++ b/test/task_viewmodel_test.dart @@ -1,6 +1,6 @@ -import 'package:flutter_test/flutter_test.dart'; import 'package:auto_gpt_flutter_client/viewmodels/task_viewmodel.dart'; import 'package:auto_gpt_flutter_client/viewmodels/mock_data.dart'; +import 'package:flutter_test/flutter_test.dart'; void main() { group('TaskViewModel', () { @@ -37,10 +37,6 @@ void main() { expect(hasNotified, true); }); - test('Simulate error happening while fetching a task', () { - // TODO: Implement once you have error handling in place in fetchTasks. - }); - test('No tasks are fetched', () { // Clear mock data for this test mockTasks.clear(); @@ -67,6 +63,7 @@ void main() { }); test('Deletes a task with invalid id', () { + // TODO: Update this test to expect an error once we have TaskService implemented final initialCount = viewModel.tasks.length; viewModel.deleteTask(9999); // Assuming no task with this id exists expect(viewModel.tasks.length, initialCount); // Count remains same