mirror of
https://github.com/foss42/apidash.git
synced 2025-12-13 00:44:56 +08:00
test: add test for all dashbot pages
This commit is contained in:
318
test/dashbot/pages/dashbot_chat_page_test.dart
Normal file
318
test/dashbot/pages/dashbot_chat_page_test.dart
Normal file
@@ -0,0 +1,318 @@
|
||||
import 'package:apidash/dashbot/core/constants/constants.dart';
|
||||
import 'package:apidash/dashbot/features/chat/models/chat_message.dart';
|
||||
import 'package:apidash/dashbot/features/chat/models/chat_state.dart';
|
||||
import 'package:apidash/dashbot/features/chat/view/pages/dashbot_chat_page.dart';
|
||||
import 'package:apidash/dashbot/features/chat/view/widgets/dashbot_task_buttons.dart';
|
||||
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
|
||||
import 'package:apidash/providers/collection_providers.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
Widget createChatScreen({
|
||||
List<Override> overrides = const [],
|
||||
ChatMessageType? initialTask,
|
||||
}) {
|
||||
return ProviderScope(
|
||||
overrides: [
|
||||
// Override the selectedRequestModelProvider to prevent Hive dependency issues
|
||||
selectedRequestModelProvider.overrideWith((ref) => null),
|
||||
...overrides,
|
||||
],
|
||||
child: MaterialApp(
|
||||
home: Scaffold(
|
||||
body: ChatScreen(initialTask: initialTask),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('ChatScreen shows empty-state prompt when idle', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('Ask me anything!'), findsOneWidget);
|
||||
expect(spy.sendMessageCalls, isEmpty);
|
||||
});
|
||||
|
||||
testWidgets('ChatScreen triggers initial task without user input',
|
||||
(tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
initialTask: ChatMessageType.generateDoc,
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
expect(spy.sendMessageCalls.length, 1);
|
||||
expect(spy.sendMessageCalls.first.text, isEmpty);
|
||||
expect(spy.sendMessageCalls.first.type, ChatMessageType.generateDoc);
|
||||
expect(spy.sendMessageCalls.first.countAsUser, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('ChatScreen toggles task suggestions panel', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(DashbotTaskButtons), findsNothing);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.help_outline_rounded));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(DashbotTaskButtons), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Clear chat icon delegates to viewmodel', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.clear_all_rounded));
|
||||
await tester.pump();
|
||||
|
||||
expect(spy.clearCalled, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('Submitting text sends general chat message', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.enterText(find.byType(TextField), 'Hello Dashbot');
|
||||
await tester.tap(find.byIcon(Icons.send_rounded));
|
||||
await tester.pump();
|
||||
|
||||
expect(spy.sendMessageCalls.length, 1);
|
||||
expect(spy.sendMessageCalls.first.text, 'Hello Dashbot');
|
||||
expect(spy.sendMessageCalls.first.type, ChatMessageType.general);
|
||||
});
|
||||
|
||||
testWidgets('Streaming state renders temporary ChatBubble', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState(
|
||||
isGenerating: true, currentStreamingResponse: 'Streaming...'));
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
final markdown =
|
||||
tester.widget<MarkdownBody>(find.byType(MarkdownBody).first);
|
||||
expect(markdown.data, 'Streaming...');
|
||||
});
|
||||
|
||||
testWidgets('Existing chat messages render in list', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
final messages = [
|
||||
ChatMessage(
|
||||
id: '1',
|
||||
content: 'First',
|
||||
role: MessageRole.user,
|
||||
timestamp: DateTime(2024),
|
||||
),
|
||||
ChatMessage(
|
||||
id: '2',
|
||||
content: 'Second',
|
||||
role: MessageRole.system,
|
||||
timestamp: DateTime(2024, 2),
|
||||
),
|
||||
];
|
||||
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setMessages(messages);
|
||||
spy.setState(ChatState(chatSessions: {'global': messages}));
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(ListView), findsOneWidget);
|
||||
expect(find.text('First'), findsOneWidget);
|
||||
expect(find.text('Second'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('TextField onSubmitted sends message', (tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.enterText(find.byType(TextField), 'Test message');
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pump();
|
||||
|
||||
expect(spy.sendMessageCalls.length, 1);
|
||||
expect(spy.sendMessageCalls.first.text, 'Test message');
|
||||
expect(spy.sendMessageCalls.first.type, ChatMessageType.general);
|
||||
});
|
||||
|
||||
testWidgets('Task suggestions panel hides when generating starts',
|
||||
(tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState());
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// First show task suggestions
|
||||
await tester.tap(find.byIcon(Icons.help_outline_rounded));
|
||||
await tester.pump();
|
||||
expect(find.byType(DashbotTaskButtons), findsOneWidget);
|
||||
|
||||
// Then start generating - this should hide the task suggestions
|
||||
spy.setState(const ChatState(isGenerating: true));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(DashbotTaskButtons), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('Scroll animation triggers on streaming response changes',
|
||||
(tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState(
|
||||
isGenerating: true,
|
||||
currentStreamingResponse: 'Initial...',
|
||||
));
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
// Change the streaming response - this should trigger scroll
|
||||
spy.setState(const ChatState(
|
||||
isGenerating: true,
|
||||
currentStreamingResponse: 'Updated streaming response...',
|
||||
));
|
||||
await tester.pump();
|
||||
|
||||
// Verify scrolling behavior by checking that the new content is rendered
|
||||
expect(find.text('Updated streaming response...'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Scroll animation triggers when generation completes',
|
||||
(tester) async {
|
||||
late SpyChatViewmodel spy;
|
||||
final messages = [
|
||||
ChatMessage(
|
||||
id: '1',
|
||||
content: 'Generated response',
|
||||
role: MessageRole.system,
|
||||
timestamp: DateTime(2024),
|
||||
),
|
||||
];
|
||||
|
||||
await tester.pumpWidget(
|
||||
createChatScreen(
|
||||
overrides: [
|
||||
chatViewmodelProvider.overrideWith((ref) {
|
||||
spy = SpyChatViewmodel(ref);
|
||||
spy.setState(const ChatState(isGenerating: true));
|
||||
return spy;
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
// Complete generation - this should trigger scroll
|
||||
spy.setMessages(messages);
|
||||
spy.setState(ChatState(
|
||||
isGenerating: false,
|
||||
chatSessions: {'global': messages},
|
||||
));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('Generated response'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
128
test/dashbot/pages/dashbot_default_page_test.dart
Normal file
128
test/dashbot/pages/dashbot_default_page_test.dart
Normal file
@@ -0,0 +1,128 @@
|
||||
import 'package:apidash/dashbot/core/common/pages/dashbot_default_page.dart';
|
||||
import 'package:apidash/dashbot/core/constants/constants.dart';
|
||||
import 'package:apidash/dashbot/core/routes/dashbot_routes.dart';
|
||||
import 'package:apidash/dashbot/features/home/view/widgets/home_screen_task_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
Finder _taskButton(String snippet) => find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is HomeScreenTaskButton && widget.label.contains(snippet),
|
||||
);
|
||||
|
||||
void main() {
|
||||
testWidgets('DashbotDefaultPage renders greeting and actions',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(home: DashbotDefaultPage()));
|
||||
|
||||
expect(find.textContaining('Hello there'), findsOneWidget);
|
||||
expect(find.textContaining('make one'), findsOneWidget);
|
||||
expect(find.textContaining('Open Chat'), findsOneWidget);
|
||||
expect(find.textContaining('Import cURL'), findsOneWidget);
|
||||
expect(find.textContaining('Import OpenAPI'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Open Chat button pushes chat route without arguments',
|
||||
(tester) async {
|
||||
final observer = RecordingNavigatorObserver();
|
||||
Object? capturedArgs;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: [observer],
|
||||
onGenerateRoute: (settings) {
|
||||
if (settings.name == DashbotRoutes.dashbotChat) {
|
||||
capturedArgs = settings.arguments;
|
||||
}
|
||||
return MaterialPageRoute(
|
||||
settings: settings,
|
||||
builder: (_) => const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
home: const DashbotDefaultPage(),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
final openChatButton = _taskButton('Open Chat');
|
||||
expect(openChatButton, findsOneWidget);
|
||||
await tester.tap(find.descendant(
|
||||
of: openChatButton,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(observer.lastRoute?.settings.name, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, isNull);
|
||||
});
|
||||
|
||||
group('Import buttons push chat route with correct arguments', () {
|
||||
testWidgets('Import cURL button', (tester) async {
|
||||
final observer = RecordingNavigatorObserver();
|
||||
Object? capturedArgs;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: [observer],
|
||||
onGenerateRoute: (settings) {
|
||||
if (settings.name == DashbotRoutes.dashbotChat) {
|
||||
capturedArgs = settings.arguments;
|
||||
}
|
||||
return MaterialPageRoute(
|
||||
settings: settings,
|
||||
builder: (_) => const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
home: const DashbotDefaultPage(),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
final importCurlButton = _taskButton('Import cURL');
|
||||
expect(importCurlButton, findsOneWidget);
|
||||
await tester.tap(find.descendant(
|
||||
of: importCurlButton,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(observer.lastRoute?.settings.name, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.importCurl);
|
||||
});
|
||||
|
||||
testWidgets('Import OpenAPI button', (tester) async {
|
||||
final observer = RecordingNavigatorObserver();
|
||||
Object? capturedArgs;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: [observer],
|
||||
onGenerateRoute: (settings) {
|
||||
if (settings.name == DashbotRoutes.dashbotChat) {
|
||||
capturedArgs = settings.arguments;
|
||||
}
|
||||
return MaterialPageRoute(
|
||||
settings: settings,
|
||||
builder: (_) => const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
home: const DashbotDefaultPage(),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
final importOpenApiButton = _taskButton('Import OpenAPI');
|
||||
expect(importOpenApiButton, findsOneWidget);
|
||||
await tester.tap(find.descendant(
|
||||
of: importOpenApiButton,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(observer.lastRoute?.settings.name, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.importOpenApi);
|
||||
});
|
||||
});
|
||||
}
|
||||
311
test/dashbot/pages/dashbot_home_page_test.dart
Normal file
311
test/dashbot/pages/dashbot_home_page_test.dart
Normal file
@@ -0,0 +1,311 @@
|
||||
import 'package:apidash/dashbot/features/home/view/pages/dashbot_home_page.dart';
|
||||
import 'package:apidash/dashbot/features/home/view/widgets/home_screen_task_button.dart';
|
||||
import 'package:apidash/dashbot/core/constants/constants.dart';
|
||||
import 'package:apidash/dashbot/core/providers/dashbot_window_notifier.dart';
|
||||
import 'package:apidash/dashbot/core/routes/dashbot_routes.dart';
|
||||
import 'package:apidash/models/request_model.dart';
|
||||
import 'package:apidash/providers/collection_providers.dart';
|
||||
import 'package:apidash_core/apidash_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../widgets/action_buttons/test_utils.dart';
|
||||
|
||||
Finder _taskButton(String snippet) => find.byWidgetPredicate(
|
||||
(widget) =>
|
||||
widget is HomeScreenTaskButton && widget.label.contains(snippet),
|
||||
);
|
||||
|
||||
Future<RecordingDashbotWindowNotifier> _pumpHomePage(
|
||||
WidgetTester tester, {
|
||||
RequestModel? selectedModel,
|
||||
void Function(String? name, Object? arguments)? onRoute,
|
||||
}) async {
|
||||
final windowNotifier = RecordingDashbotWindowNotifier();
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
dashbotWindowNotifierProvider.overrideWith((ref) => windowNotifier),
|
||||
selectedRequestModelProvider.overrideWith((ref) => selectedModel),
|
||||
],
|
||||
child: MaterialApp(
|
||||
onGenerateRoute: (settings) {
|
||||
onRoute?.call(settings.name, settings.arguments);
|
||||
return MaterialPageRoute(
|
||||
settings: settings,
|
||||
builder: (_) => const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
home: const Scaffold(body: DashbotHomePage()),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
return windowNotifier;
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('DashbotHomePage renders greeting and quick actions',
|
||||
(tester) async {
|
||||
await _pumpHomePage(tester, onRoute: (_, __) {});
|
||||
|
||||
expect(find.textContaining('Hello there'), findsOneWidget);
|
||||
expect(find.textContaining('How can I help you today'), findsOneWidget);
|
||||
// Note: 'Chat with Dashbot' is only available in debug mode, so we don't test for it here
|
||||
expect(find.textContaining('Explain me this response'), findsOneWidget);
|
||||
expect(find.textContaining('Generate documentation'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Chat with Dashbot button appears and works in debug mode',
|
||||
(tester) async {
|
||||
// In debug mode (which tests run in), the button should be present
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
// The button should be visible in debug mode
|
||||
final buttonFinder = _taskButton('Chat with Dashbot');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
// Tap the button
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Should navigate to chat without any initial task arguments
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, isNull);
|
||||
});
|
||||
|
||||
group('Quick action buttons navigate with correct arguments', () {
|
||||
testWidgets('Explain me this response button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Explain me this response');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.explainResponse);
|
||||
});
|
||||
|
||||
testWidgets('Help me debug this error button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Help me debug this error');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.debugError);
|
||||
});
|
||||
|
||||
testWidgets('Generate documentation button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Generate documentation');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.generateDoc);
|
||||
});
|
||||
|
||||
testWidgets('Generate Tests button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Generate Tests');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.generateTest);
|
||||
});
|
||||
|
||||
testWidgets('Generate Code button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Generate Code');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.generateCode);
|
||||
});
|
||||
|
||||
testWidgets('Import cURL button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Import cURL');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.importCurl);
|
||||
});
|
||||
|
||||
testWidgets('Import OpenAPI button', (tester) async {
|
||||
String? capturedRoute;
|
||||
Object? capturedArgs;
|
||||
|
||||
await _pumpHomePage(
|
||||
tester,
|
||||
onRoute: (name, arguments) {
|
||||
capturedRoute = name;
|
||||
capturedArgs = arguments;
|
||||
},
|
||||
);
|
||||
|
||||
final buttonFinder = _taskButton('Import OpenAPI');
|
||||
expect(buttonFinder, findsOneWidget);
|
||||
|
||||
await tester.tap(find.descendant(
|
||||
of: buttonFinder,
|
||||
matching: find.byType(TextButton),
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(capturedRoute, DashbotRoutes.dashbotChat);
|
||||
expect(capturedArgs, ChatMessageType.importOpenApi);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Generate Tool hides and shows dashbot window even without response',
|
||||
(tester) async {
|
||||
final notifier = await _pumpHomePage(tester, onRoute: (_, __) {});
|
||||
|
||||
await tester.tap(find.text('🛠️ Generate Tool'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(notifier.hideCalls, 1);
|
||||
expect(notifier.showCalls, 1);
|
||||
});
|
||||
|
||||
testWidgets('Generate UI opens dialog and restores dashbot window',
|
||||
(tester) async {
|
||||
final responseModel = const HttpResponseModel(
|
||||
body: 'example response',
|
||||
formattedBody: 'formatted',
|
||||
);
|
||||
final requestModel = RequestModel(
|
||||
id: 'req-1',
|
||||
httpRequestModel: const HttpRequestModel(),
|
||||
httpResponseModel: responseModel,
|
||||
);
|
||||
|
||||
final notifier = await _pumpHomePage(
|
||||
tester,
|
||||
selectedModel: requestModel,
|
||||
onRoute: (_, __) {},
|
||||
);
|
||||
|
||||
await tester.tap(find.text('📱 Generate UI'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(Dialog), findsOneWidget);
|
||||
|
||||
final dialogElement = find.byType(Dialog);
|
||||
if (dialogElement.evaluate().isNotEmpty) {
|
||||
Navigator.of(dialogElement.evaluate().first).pop();
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
expect(notifier.hideCalls, 1);
|
||||
expect(notifier.showCalls, 1);
|
||||
});
|
||||
}
|
||||
51
test/dashbot/pages/test_utils.dart
Normal file
51
test/dashbot/pages/test_utils.dart
Normal file
@@ -0,0 +1,51 @@
|
||||
import 'package:apidash/dashbot/features/chat/models/chat_message.dart';
|
||||
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
|
||||
import 'package:apidash/dashbot/features/chat/models/chat_state.dart';
|
||||
import 'package:apidash/dashbot/core/constants/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SpyChatViewmodel extends ChatViewmodel {
|
||||
SpyChatViewmodel(super.ref);
|
||||
|
||||
final List<({String text, ChatMessageType type, bool countAsUser})>
|
||||
sendMessageCalls = [];
|
||||
|
||||
bool clearCalled = false;
|
||||
List<ChatMessage> _messages = const [];
|
||||
|
||||
void setMessages(List<ChatMessage> messages) {
|
||||
_messages = messages;
|
||||
state = state.copyWith(chatSessions: {'global': messages});
|
||||
}
|
||||
|
||||
void setState(ChatState newState) {
|
||||
state = newState;
|
||||
}
|
||||
|
||||
@override
|
||||
List<ChatMessage> get currentMessages => _messages;
|
||||
|
||||
@override
|
||||
Future<void> sendMessage({
|
||||
required String text,
|
||||
ChatMessageType type = ChatMessageType.general,
|
||||
bool countAsUser = true,
|
||||
}) async {
|
||||
sendMessageCalls.add((text: text, type: type, countAsUser: countAsUser));
|
||||
}
|
||||
|
||||
@override
|
||||
void clearCurrentChat() {
|
||||
clearCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
class RecordingNavigatorObserver extends NavigatorObserver {
|
||||
Route<dynamic>? lastRoute;
|
||||
|
||||
@override
|
||||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
super.didPush(route, previousRoute);
|
||||
lastRoute = route;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user