tests: add tests for dashbot action buttons(cv: 95.5)

This commit is contained in:
Udhay-Adithya
2025-09-25 18:46:16 +05:30
parent 7902a6b32a
commit 74366454f8
11 changed files with 981 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_add_test_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
const action = ChatAction(
action: 'add_test',
target: 'test',
actionType: ChatActionType.other,
targetType: ChatActionTarget.test,
);
group('DashbotAddTestButton', () {
testWidgets('renders label and invokes applyAutoFix on press',
(tester) async {
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotAddTestButton(action: action),
),
),
),
);
expect(find.text('Add Test'), findsOneWidget);
expect(find.byIcon(Icons.playlist_add_check), findsOneWidget);
await tester.tap(find.text('Add Test'));
await tester.pump();
expect(notifier.applyAutoFixCalls.single, same(action));
});
});
}

View File

@@ -0,0 +1,106 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_apply_curl_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('DashbotApplyCurlButton', () {
testWidgets('uses default Apply label and triggers auto-fix',
(tester) async {
const action = ChatAction(
action: 'apply_curl',
target: 'httpRequestModel',
actionType: ChatActionType.applyCurl,
targetType: ChatActionTarget.httpRequestModel,
);
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotApplyCurlButton(action: action),
),
),
),
);
expect(find.text('Apply'), findsOneWidget);
await tester.tap(find.text('Apply'));
await tester.pump();
expect(notifier.applyAutoFixCalls, hasLength(1));
expect(notifier.applyAutoFixCalls.single, same(action));
});
testWidgets('shows Create New Request when field=apply_to_new',
(tester) async {
const action = ChatAction(
action: 'apply_curl',
target: 'httpRequestModel',
field: 'apply_to_new',
actionType: ChatActionType.applyCurl,
targetType: ChatActionTarget.httpRequestModel,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotApplyCurlButton(action: action),
),
),
),
);
expect(find.text('Create New Request'), findsOneWidget);
});
testWidgets('uses path text when selecting operation', (tester) async {
const action = ChatAction(
action: 'apply_curl',
target: 'httpRequestModel',
field: 'select_operation',
path: '/users',
actionType: ChatActionType.applyCurl,
targetType: ChatActionTarget.httpRequestModel,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotApplyCurlButton(action: action),
),
),
),
);
expect(find.text('/users'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,104 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_apply_openapi_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('DashbotApplyOpenApiButton', () {
testWidgets('defaults to Apply label and invokes auto fix', (tester) async {
const action = ChatAction(
action: 'apply_openapi',
target: 'httpRequestModel',
actionType: ChatActionType.applyOpenApi,
targetType: ChatActionTarget.httpRequestModel,
);
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotApplyOpenApiButton(action: action),
),
),
),
);
expect(find.text('Apply'), findsOneWidget);
await tester.tap(find.text('Apply'));
await tester.pump();
expect(notifier.applyAutoFixCalls.single, same(action));
});
testWidgets('shows Create New Request label when requested',
(tester) async {
const action = ChatAction(
action: 'apply_openapi',
target: 'httpRequestModel',
field: 'apply_to_new',
actionType: ChatActionType.applyOpenApi,
targetType: ChatActionTarget.httpRequestModel,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotApplyOpenApiButton(action: action),
),
),
),
);
expect(find.text('Create New Request'), findsOneWidget);
});
testWidgets('shows Apply to Selected label when field=apply_to_selected',
(tester) async {
const action = ChatAction(
action: 'apply_openapi',
target: 'httpRequestModel',
field: 'apply_to_selected',
actionType: ChatActionType.applyOpenApi,
targetType: ChatActionTarget.httpRequestModel,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotApplyOpenApiButton(action: action),
),
),
),
);
expect(find.text('Apply to Selected'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,54 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_auto_fix_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
const action = ChatAction(
action: 'update_field',
target: 'httpRequestModel',
field: 'url',
value: 'https://api.apidash.dev/users',
actionType: ChatActionType.updateField,
targetType: ChatActionTarget.httpRequestModel,
);
group('DashbotAutoFixButton', () {
testWidgets('renders icon, label and triggers auto-fix', (tester) async {
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotAutoFixButton(action: action),
),
),
),
);
expect(find.text('Auto Fix'), findsOneWidget);
expect(find.byIcon(Icons.auto_fix_high), findsOneWidget);
await tester.tap(find.text('Auto Fix'));
await tester.pump();
expect(notifier.applyAutoFixCalls, hasLength(1));
expect(notifier.applyAutoFixCalls.single, same(action));
});
});
}

View File

@@ -0,0 +1,91 @@
import 'dart:io';
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_download_doc_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late Directory tempDownloadsDir;
setUp(() {
tempDownloadsDir = Directory.systemTemp.createTempSync('dashbot_download');
});
tearDown(() {
if (tempDownloadsDir.existsSync()) {
tempDownloadsDir.deleteSync(recursive: true);
}
});
group('DashbotDownloadDocButton', () {
testWidgets('disables download when content is empty', (tester) async {
const action = ChatAction(
action: 'download_doc',
target: 'code',
path: 'doc',
value: '',
actionType: ChatActionType.downloadDoc,
targetType: ChatActionTarget.code,
);
await tester.pumpWidget(
ProviderScope(
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotDownloadDocButton(action: action),
),
),
),
);
final buttonFinder =
find.byWidgetPredicate((widget) => widget is ButtonStyleButton);
final button = tester.widget<ButtonStyleButton>(buttonFinder);
expect(button.onPressed, isNull);
});
// testWidgets('saves documentation to downloads directory', (tester) async {
// const action = ChatAction(
// action: 'download_doc',
// target: 'code',
// path: 'api-docs',
// value: '# Markdown',
// actionType: ChatActionType.downloadDoc,
// targetType: ChatActionTarget.code,
// );
// await tester.pumpWidget(
// ProviderScope(
// child: MaterialApp(
// theme: kThemeDataLight,
// home: const Scaffold(
// body: DashbotDownloadDocButton(action: action),
// ),
// ),
// ),
// );
// final buttonFinder =
// find.byWidgetPredicate((widget) => widget is ButtonStyleButton);
// final button = tester.widget<ButtonStyleButton>(buttonFinder);
// expect(button.onPressed, isNotNull);
// await tester.tap(find.text('Download Documentation'));
// await tester.pumpAndSettle();
// final savedPath =
// '${tempDownloadsDir.path}${Platform.pathSeparator}api-docs.md';
// final savedFile = File(savedPath);
// expect(savedFile.existsSync(), isTrue);
// expect(savedFile.readAsStringSync(), '# Markdown');
// });
});
}

View File

@@ -0,0 +1,54 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_generate_codeblock.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('DashbotGeneratedCodeBlock', () {
testWidgets('shows provided code value', (tester) async {
const action = ChatAction(
action: 'other',
target: 'code',
value: 'print("hello")',
actionType: ChatActionType.other,
targetType: ChatActionTarget.code,
);
await tester.pumpWidget(
MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotGeneratedCodeBlock(action: action),
),
),
);
expect(find.text('print("hello")'), findsOneWidget);
});
testWidgets('falls back to placeholder when value missing', (tester) async {
const action = ChatAction(
action: 'other',
target: 'code',
actionType: ChatActionType.other,
targetType: ChatActionTarget.code,
);
await tester.pumpWidget(
MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotGeneratedCodeBlock(action: action),
),
),
);
expect(find.text('// No code returned'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,87 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_generate_language_picker_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('DashbotGenerateLanguagePicker', () {
testWidgets('renders provided language options and sends message on tap',
(tester) async {
const action = ChatAction(
action: 'show_languages',
target: 'codegen',
value: ['Python (requests)', 'cURL'],
actionType: ChatActionType.showLanguages,
targetType: ChatActionTarget.codegen,
);
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotGenerateLanguagePicker(action: action),
),
),
),
);
expect(find.text('Python (requests)'), findsOneWidget);
expect(find.text('cURL'), findsOneWidget);
await tester.tap(find.text('Python (requests)'));
await tester.pump();
expect(notifier.sendMessageCalls, hasLength(1));
final call = notifier.sendMessageCalls.single;
expect(call.text, 'Please generate code in Python (requests)');
expect(call.type, ChatMessageType.generateCode);
expect(call.countAsUser, isTrue);
});
testWidgets('falls back to default language list', (tester) async {
const action = ChatAction(
action: 'show_languages',
target: 'codegen',
value: 'unexpected',
actionType: ChatActionType.showLanguages,
targetType: ChatActionTarget.codegen,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotGenerateLanguagePicker(action: action),
),
),
),
);
expect(find.text('JavaScript (fetch)'), findsOneWidget);
expect(find.text('Python (requests)'), findsOneWidget);
expect(find.text('Dart (http)'), findsOneWidget);
expect(find.text('Go (net/http)'), findsOneWidget);
expect(find.text('cURL'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,96 @@
import 'dart:ui';
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_import_now_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/core/providers/dashbot_window_notifier.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
const specJson = '''
{
"openapi": "3.0.0",
"info": {"title": "Sample API", "version": "1.0.0"},
"servers": [{"url": "https://api.apidash.dev"}],
"paths": {
"/users": {
"get": {
"responses": {"200": {"description": "OK"}}
}
}
}
}
''';
group('DashbotImportNowButton', () {
testWidgets('hides dashbot window, shows picker, applies selected ops',
(tester) async {
const action = ChatAction(
action: 'import_now_openapi',
target: 'httpRequestModel',
value: {'sourceName': 'Sample', 'content': specJson},
actionType: ChatActionType.other,
targetType: ChatActionTarget.httpRequestModel,
);
late TestChatViewmodel notifier;
late RecordingDashbotWindowNotifier windowNotifier;
final binding = TestWidgetsFlutterBinding.ensureInitialized();
binding.window.physicalSizeTestValue = const Size(1600, 1200);
binding.window.devicePixelRatioTestValue = 1.0;
addTearDown(() {
binding.window.clearPhysicalSizeTestValue();
binding.window.clearDevicePixelRatioTestValue();
});
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
dashbotWindowNotifierProvider.overrideWith((ref) {
windowNotifier = RecordingDashbotWindowNotifier();
return windowNotifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotImportNowButton(action: action),
),
),
),
);
await tester.tap(find.text('Import Now'));
await tester.pumpAndSettle();
// Dialog should be shown; tap Import to accept default selection
final importFinder = find.text('Import');
expect(importFinder, findsOneWidget);
await tester.tap(importFinder);
await tester.pumpAndSettle();
expect(windowNotifier.hideCalls, greaterThanOrEqualTo(1));
expect(windowNotifier.showCalls, greaterThanOrEqualTo(1));
expect(notifier.applyAutoFixCalls, isNotEmpty);
final applied = notifier.applyAutoFixCalls.single;
expect(applied.action, 'apply_openapi');
expect(applied.field, 'apply_to_new');
expect(applied.value, isA<Map<String, dynamic>>());
final value = applied.value as Map<String, dynamic>;
expect(value['url'], 'https://api.apidash.dev/users');
expect(value['method'], 'GET');
});
});
}

View File

@@ -0,0 +1,79 @@
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dsahbot_select_operation_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('DashbotSelectOperationButton', () {
testWidgets('renders operation label and applies auto fix', (tester) async {
const action = ChatAction(
action: 'select_operation',
target: 'httpRequestModel',
field: 'select_operation',
path: 'GET /users',
actionType: ChatActionType.applyOpenApi,
targetType: ChatActionTarget.httpRequestModel,
);
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotSelectOperationButton(action: action),
),
),
),
);
expect(find.text('GET /users'), findsOneWidget);
await tester.tap(find.text('GET /users'));
await tester.pump();
expect(notifier.applyAutoFixCalls.single, same(action));
});
testWidgets('falls back to Unknown label when path missing',
(tester) async {
const action = ChatAction(
action: 'select_operation',
target: 'httpRequestModel',
field: 'select_operation',
actionType: ChatActionType.applyOpenApi,
targetType: ChatActionTarget.httpRequestModel,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotSelectOperationButton(action: action),
),
),
),
);
expect(find.text('Unknown'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,203 @@
import 'dart:typed_data';
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:apidash/dashbot/core/common/widgets/dashbot_action_buttons/dashbot_upload_requests_button.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import '../../../test_consts.dart';
import 'test_utils.dart';
class FakeFileSelectorPlatform extends FileSelectorPlatform {
FakeFileSelectorPlatform({this.fileToReturn});
XFile? fileToReturn;
List<XTypeGroup>? lastAcceptedTypeGroups;
@override
Future<XFile?> openFile({
List<XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? confirmButtonText,
}) async {
lastAcceptedTypeGroups = acceptedTypeGroups;
return fileToReturn;
}
@override
Future<List<XFile>> openFiles({
List<XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? confirmButtonText,
}) async {
lastAcceptedTypeGroups = acceptedTypeGroups;
return fileToReturn == null ? <XFile>[] : <XFile>[fileToReturn!];
}
@override
Future<String?> getDirectoryPath({
String? initialDirectory,
String? confirmButtonText,
}) async =>
null;
@override
Future<List<String>> getDirectoryPaths({
String? initialDirectory,
String? confirmButtonText,
}) async =>
<String>[];
@override
Future<String?> getSavePath({
List<XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? suggestedName,
String? confirmButtonText,
}) async =>
null;
@override
Future<FileSaveLocation?> getSaveLocation({
List<XTypeGroup>? acceptedTypeGroups,
SaveDialogOptions options = const SaveDialogOptions(),
}) async =>
null;
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late FakeFileSelectorPlatform fakePlatform;
setUp(() {
fakePlatform = FakeFileSelectorPlatform();
FileSelectorPlatform.instance = fakePlatform;
});
group('DashbotUploadRequestButton', () {
testWidgets('uploads OpenAPI attachment and forwards to chat viewmodel',
(tester) async {
final bytes = Uint8List.fromList('openapi spec'.codeUnits);
fakePlatform.fileToReturn = XFile.fromData(bytes,
name: 'spec.yaml', mimeType: 'application/yaml');
const action = ChatAction(
action: 'upload_asset',
target: 'attachment',
field: 'openapi_spec',
value: {
'purpose': 'OpenAPI specification',
'accepted_types': ['application/yaml']
},
actionType: ChatActionType.uploadAsset,
targetType: ChatActionTarget.attachment,
);
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotUploadRequestButton(action: action),
),
),
),
);
await tester.tap(find.text('Upload: OpenAPI specification'));
await tester.pump();
expect(fakePlatform.lastAcceptedTypeGroups, isNotNull);
final group = fakePlatform.lastAcceptedTypeGroups!.single;
expect(group.mimeTypes, ['application/yaml']);
expect(notifier.openApiAttachmentCalls, hasLength(1));
final attachment = notifier.openApiAttachmentCalls.single;
expect(attachment.mimeType, 'application/yaml');
expect(attachment.sizeBytes, bytes.length);
});
testWidgets('sends message for non-openapi uploads', (tester) async {
fakePlatform.fileToReturn =
XFile.fromData(Uint8List.fromList([1, 2, 3]), name: 'data.bin');
const action = ChatAction(
action: 'upload_asset',
target: 'attachment',
value: {'purpose': 'Sample upload'},
actionType: ChatActionType.uploadAsset,
targetType: ChatActionTarget.attachment,
);
late TestChatViewmodel notifier;
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) {
notifier = TestChatViewmodel(ref);
return notifier;
}),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotUploadRequestButton(action: action),
),
),
),
);
await tester.tap(find.text('Upload: Sample upload'));
await tester.pump();
expect(notifier.sendMessageCalls, hasLength(1));
final call = notifier.sendMessageCalls.single;
expect(call.type, ChatMessageType.general);
expect(call.text, contains('Attached file'));
expect(call.text, contains('size=3'));
});
testWidgets('does nothing when user cancels file picker', (tester) async {
fakePlatform.fileToReturn = null;
const action = ChatAction(
action: 'upload_asset',
target: 'attachment',
actionType: ChatActionType.uploadAsset,
targetType: ChatActionTarget.attachment,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
chatViewmodelProvider.overrideWith((ref) => TestChatViewmodel(ref)),
],
child: MaterialApp(
theme: kThemeDataLight,
home: Scaffold(
body: DashbotUploadRequestButton(action: action),
),
),
),
);
await tester.tap(find.text('Upload Attachment'));
await tester.pump();
// No exceptions and no attachments created
});
});
}

View File

@@ -0,0 +1,55 @@
import 'package:apidash/dashbot/core/model/chat_attachment.dart';
import 'package:apidash/dashbot/core/providers/dashbot_window_notifier.dart';
import 'package:apidash/dashbot/features/chat/models/chat_action.dart';
import 'package:apidash/dashbot/features/chat/viewmodel/chat_viewmodel.dart';
import 'package:apidash/dashbot/core/constants/constants.dart';
class TestChatViewmodel extends ChatViewmodel {
TestChatViewmodel(super.ref);
final List<ChatAction> applyAutoFixCalls = [];
final List<({String text, ChatMessageType type, bool countAsUser})>
sendMessageCalls = [];
final List<ChatAttachment> openApiAttachmentCalls = [];
bool throwOnApplyAutoFix = false;
@override
Future<void> applyAutoFix(ChatAction action) async {
applyAutoFixCalls.add(action);
if (throwOnApplyAutoFix) {
throw Exception('applyAutoFix error');
}
}
@override
Future<void> sendMessage({
required String text,
ChatMessageType type = ChatMessageType.general,
bool countAsUser = true,
}) async {
sendMessageCalls.add((text: text, type: type, countAsUser: countAsUser));
}
@override
Future<void> handleOpenApiAttachment(ChatAttachment att) async {
openApiAttachmentCalls.add(att);
}
}
class RecordingDashbotWindowNotifier extends DashbotWindowNotifier {
int hideCalls = 0;
int showCalls = 0;
@override
void hide() {
hideCalls += 1;
super.hide();
}
@override
void show() {
showCalls += 1;
super.show();
}
}