mirror of
https://github.com/foss42/apidash.git
synced 2025-12-10 07:08:08 +08:00
tests: add tests for dashbot action buttons(cv: 95.5)
This commit is contained in:
@@ -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));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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');
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
55
test/dashbot/widgets/action_buttons/test_utils.dart
Normal file
55
test/dashbot/widgets/action_buttons/test_utils.dart
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user