From a70b8251721339a72d6fe2f6ab1305ea9a0a1cd1 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 25 Sep 2025 16:27:07 +0530 Subject: [PATCH] tests: add tests for dashbot utils(cv: 100) --- test/dashbot/utils/dashbot_icons_test.dart | 30 ++++++ .../utils/safe_parse_json_message_test.dart | 37 ++++++++ test/dashbot/utils/show_dashbot_test.dart | 92 +++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 test/dashbot/utils/dashbot_icons_test.dart create mode 100644 test/dashbot/utils/safe_parse_json_message_test.dart create mode 100644 test/dashbot/utils/show_dashbot_test.dart diff --git a/test/dashbot/utils/dashbot_icons_test.dart b/test/dashbot/utils/dashbot_icons_test.dart new file mode 100644 index 00000000..94dcc61e --- /dev/null +++ b/test/dashbot/utils/dashbot_icons_test.dart @@ -0,0 +1,30 @@ +import 'package:apidash/dashbot/core/utils/dashbot_icons.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('DashbotIcons', () { + test('path getters', () { + expect(DashbotIcons.dashbotIcon1, 'assets/dashbot/dashbot_icon_1.png'); + expect(DashbotIcons.dashbotIcon2, 'assets/dashbot/dashbot_icon_2.png'); + }); + + test('getDashbotIcon1 returns Image.asset with correct dimensions', () { + final img = DashbotIcons.getDashbotIcon1(width: 24, height: 24); + expect(img, isA()); + expect(img.width, 24); + expect(img.height, 24); + final provider = img.image; + expect(provider, isA()); + expect((provider as AssetImage).assetName, DashbotIcons.dashbotIcon1); + }); + + test('getDashbotIcon2 returns Image.asset', () { + final img = DashbotIcons.getDashbotIcon2(); + expect(img.image, isA()); + expect((img.image as AssetImage).assetName, DashbotIcons.dashbotIcon2); + }); + }); +} diff --git a/test/dashbot/utils/safe_parse_json_message_test.dart b/test/dashbot/utils/safe_parse_json_message_test.dart new file mode 100644 index 00000000..137e3caa --- /dev/null +++ b/test/dashbot/utils/safe_parse_json_message_test.dart @@ -0,0 +1,37 @@ +import 'package:apidash/dashbot/core/utils/safe_parse_json_message.dart'; +import 'package:test/test.dart'; + +void main() { + group('MessageJson.safeParse', () { + test('parses valid JSON object', () { + final m = MessageJson.safeParse('{"a":1,"b":"x"}'); + expect(m, containsPair('a', 1)); + expect(m['b'], 'x'); + }); + + test('returns empty map for non-object top-level JSON', () { + final m = MessageJson.safeParse('[1,2,3]'); + expect(m, isEmpty); + }); + + test('extracts object from markdown fenced code block', () { + const input = + '''Here is your result:\n```json\n{\n "ok": true,\n "count": 2\n}\n```\nThanks'''; + final m = MessageJson.safeParse(input); + expect(m['ok'], true); + expect(m['count'], 2); + }); + + test('throws FormatException on invalid JSON with no braces slice', () { + expect(() => MessageJson.safeParse('totally invalid'), + throwsFormatException); + }); + + test('falls back to slice between first { and last }', () { + const input = 'prefix {"z":42, "k":"v"} suffix'; + final m = MessageJson.safeParse(input); + expect(m['z'], 42); + expect(m['k'], 'v'); + }); + }); +} diff --git a/test/dashbot/utils/show_dashbot_test.dart b/test/dashbot/utils/show_dashbot_test.dart new file mode 100644 index 00000000..32af46db --- /dev/null +++ b/test/dashbot/utils/show_dashbot_test.dart @@ -0,0 +1,92 @@ +import 'package:apidash/dashbot/core/providers/dashbot_window_notifier.dart'; +import 'package:apidash/dashbot/core/utils/show_dashbot.dart'; +import 'package:apidash/dashbot/dashbot_dashboard.dart'; +import 'package:apidash/providers/collection_providers.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + Future<(BuildContext, WidgetRef)> pumpHarness( + WidgetTester tester, { + List? overrides, + }) async { + late BuildContext ctx; + late WidgetRef wRef; + await tester.pumpWidget(ProviderScope( + overrides: [ + // Empty current request (StateProvider override supplies initial value). + selectedRequestModelProvider.overrideWith((ref) => null), + if (overrides != null) ...overrides, + ], + child: MaterialApp( + home: Scaffold( + body: Consumer(builder: (c, ref, _) { + ctx = c; + wRef = ref; + return const SizedBox(); + }), + ), + ), + )); + // Enlarge window width to avoid Row overflow in header (actions + title) + final notifier = wRef.read(dashbotWindowNotifierProvider.notifier); + notifier.state = notifier.state.copyWith(width: 650); + return (ctx, wRef); + } + + group('showDashbotWindow', () { + testWidgets('activates & inserts overlay when inactive & popped', + (tester) async { + final (ctx, ref) = await pumpHarness(tester); + expect(ref.read(dashbotWindowNotifierProvider).isActive, isFalse); + showDashbotWindow(ctx, ref); + await tester.pump(); + // State toggled active + expect(ref.read(dashbotWindowNotifierProvider).isActive, isTrue); + // DashBot title text present (from DashbotWindow) + expect(find.text('DashBot'), findsOneWidget); + }); + + testWidgets('early return when already active', (tester) async { + final (ctx, ref) = await pumpHarness(tester); + // Manually set active before calling util to hit early return. + ref.read(dashbotWindowNotifierProvider.notifier).toggleActive(); + final before = ref.read(dashbotWindowNotifierProvider); + showDashbotWindow(ctx, ref); + await tester.pump(); + final after = ref.read(dashbotWindowNotifierProvider); + expect(after.isActive, isTrue); + // No duplicate activation toggling (remains same instance/state) + expect(after.isActive, before.isActive); + }); + + testWidgets('early return when not popped', (tester) async { + final (ctx, ref) = await pumpHarness(tester); + // Toggle popped to false + ref.read(dashbotWindowNotifierProvider.notifier).togglePopped(); + expect(ref.read(dashbotWindowNotifierProvider).isPopped, isFalse); + showDashbotWindow(ctx, ref); + await tester.pump(); + // Still inactive because not popped + expect(ref.read(dashbotWindowNotifierProvider).isActive, isFalse); + expect(find.byType(DashbotWindow), findsNothing); + }); + + testWidgets('pressing close button removes overlay & deactivates', + (tester) async { + final (ctx, ref) = await pumpHarness(tester); + showDashbotWindow(ctx, ref); + await tester.pump(); + expect(ref.read(dashbotWindowNotifierProvider).isActive, isTrue); + // Tap the close (Icons.close) + final closeFinder = find.byIcon(Icons.close); + expect(closeFinder, findsOneWidget); + await tester.tap(closeFinder); + await tester.pump(); + expect(ref.read(dashbotWindowNotifierProvider).isActive, isFalse); + }); + }); +}