From b616f57df57d123af5cdc2923a1e8e395431ff9b Mon Sep 17 00:00:00 2001 From: Jatin Date: Fri, 31 Oct 2025 22:59:50 +0530 Subject: [PATCH] test: add unit & widget tests for SavePageDialog functionality --- test/ui/screens/save_page_dialog_test.dart | 247 +++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 test/ui/screens/save_page_dialog_test.dart diff --git a/test/ui/screens/save_page_dialog_test.dart b/test/ui/screens/save_page_dialog_test.dart new file mode 100644 index 0000000..b437c72 --- /dev/null +++ b/test/ui/screens/save_page_dialog_test.dart @@ -0,0 +1,247 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:mockito/mockito.dart'; +import 'package:texterra/cubit/canvas_state.dart'; +import 'package:texterra/ui/screens/save_page_dialog.dart'; + +import 'package:texterra/cubit/canvas_cubit.dart'; + +import 'saved_pages_test.mocks.dart'; + +void main() { + late MockCanvasCubit mockCanvasCubit; + + setUp(() { + mockCanvasCubit = MockCanvasCubit(); + when(mockCanvasCubit.stream).thenAnswer((_) => const Stream.empty()); + when(mockCanvasCubit.state).thenReturn(CanvasState.initial()); + }); + + Widget createTestWidget() { + return MaterialApp( + home: BlocProvider.value( + value: mockCanvasCubit, + child: Builder( + builder: (context) => Scaffold( + body: Center( + child: ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (_) => BlocProvider.value( + value: mockCanvasCubit, + child: const SavePageDialog(), + ), + ); + }, + child: const Text('Open Dialog'), + ), + ), + ), + ), + ), + ); + } + + Future openDialog(WidgetTester tester) async { + await tester.tap(find.text('Open Dialog')); + await tester.pumpAndSettle(); + } + + group('SavePageDialog', () { + testWidgets('renders dialog with all basic UI elements', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + expect(find.text('Save Page'), findsOneWidget); + expect(find.byIcon(Icons.save), findsOneWidget); + expect(find.byType(TextFormField), findsNWidgets(2)); + expect(find.text('Cancel'), findsOneWidget); + expect(find.text('Save'), findsOneWidget); + }); + + testWidgets('shows validation error for empty page name', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + expect(find.text('Please enter a page name'), findsOneWidget); + }); + + testWidgets('shows validation error for invalid characters', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'Invalid<>'); + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + expect( + find.text('Page name contains invalid characters'), findsOneWidget); + }); + + testWidgets('cancel button closes the dialog', (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + expect(find.byType(SavePageDialog), findsOneWidget); + + await tester.tap(find.text('Cancel')); + await tester.pumpAndSettle(); + + expect(find.byType(SavePageDialog), findsNothing); + }); + + testWidgets('saves valid page name and closes dialog', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + when(mockCanvasCubit.savePage(any, + label: anyNamed('label'), color: anyNamed('color'))) + .thenAnswer((_) async => Future.value()); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'My Page'); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + expect(find.byType(SavePageDialog), findsNothing); + }); + + testWidgets('shows overwrite confirmation for existing page', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()) + .thenAnswer((_) async => ['Existing Page']); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'Existing Page'); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + expect(find.text('Page Already Exists'), findsOneWidget); + expect(find.byIcon(Icons.warning), findsOneWidget); + expect(find.text('Overwrite'), findsOneWidget); + }); + + testWidgets('canceling overwrite keeps dialog open', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()) + .thenAnswer((_) async => ['Existing Page']); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'Existing Page'); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Cancel').last); + await tester.pumpAndSettle(); + + expect(find.byType(SavePageDialog), findsOneWidget); + }); + + testWidgets('confirming overwrite saves and closes dialog', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()) + .thenAnswer((_) async => ['Existing Page']); + when(mockCanvasCubit.savePage(any, + label: anyNamed('label'), color: anyNamed('color'))) + .thenAnswer((_) async => Future.value()); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'Existing Page'); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Overwrite')); + await tester.pumpAndSettle(); + + expect(find.byType(SavePageDialog), findsNothing); + }); + + testWidgets('displays color selection options', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + expect(find.text('Choose a color: '), findsOneWidget); + + final containers = find.byWidgetPredicate( + (widget) => + widget is Container && + widget.decoration is BoxDecoration && + (widget.decoration as BoxDecoration).shape == BoxShape.circle, + ); + + expect(containers, findsNWidgets(6)); + }); + + testWidgets('saves with both name and label', (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + when(mockCanvasCubit.savePage(any, + label: anyNamed('label'), color: anyNamed('color'))) + .thenAnswer((_) async => Future.value()); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'Page Name'); + await tester.enterText(find.byType(TextFormField).at(1), 'My Label'); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + expect(find.byType(SavePageDialog), findsNothing); + }); + + testWidgets('handles save error and keeps dialog open', + (WidgetTester tester) async { + when(mockCanvasCubit.getSavedPages()).thenAnswer((_) async => []); + when(mockCanvasCubit.savePage(any, + label: anyNamed('label'), color: anyNamed('color'))) + .thenThrow(Exception('Save failed')); + + await tester.pumpWidget(createTestWidget()); + await openDialog(tester); + + await tester.enterText(find.byType(TextFormField).first, 'Test Page'); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + + expect(find.byType(SavePageDialog), findsOneWidget); + }); + }); +}