From d6bb64b3bcb421dbf80c20dc84c595bff337c3c7 Mon Sep 17 00:00:00 2001 From: insleker Date: Mon, 15 Dec 2025 11:55:19 +0800 Subject: [PATCH] test: resolve error for `flutter test` after upgrade to riverpod3 --- .../repositories/preferences_repository.dart | 66 ++++++--- .../pdf/view_model/pdf_view_model.dart | 6 +- .../pdf/view_model/pdf_view_state.dart | 7 +- .../pdf/widgets/pdf_viewer_widget.dart | 4 + .../pdf/widgets/signature_overlay.dart | 8 +- test/features/_test_helper.dart | 31 ++-- test/features/step/_world.dart | 38 +++-- ..._the_page_based_on_the_signature_card.dart | 5 +- ...lected_signature_placement_is_removed.dart | 5 +- test/features/step/the_app_launches.dart | 39 ++--- ...signature_placements_remain_unchanged.dart | 5 +- ...opens_a_different_document_with_pages.dart | 2 +- test/widget/export_flow_test.dart | 40 ++++-- test/widget/helpers.dart | 134 ++++++++++++------ test/widget/pdf_navigation_widget_test.dart | 21 +-- .../widget/pdf_page_area_early_jump_test.dart | 19 ++- test/widget/pdf_page_area_jump_test.dart | 19 ++- test/widget/pdf_page_area_test.dart | 28 ++-- test/widget/signature_overlay_test.dart | 8 +- 19 files changed, 306 insertions(+), 179 deletions(-) diff --git a/lib/data/repositories/preferences_repository.dart b/lib/data/repositories/preferences_repository.dart index 6cf4212..ec3c9df 100644 --- a/lib/data/repositories/preferences_repository.dart +++ b/lib/data/repositories/preferences_repository.dart @@ -90,12 +90,17 @@ String _normalizeLanguageTag(String tag) { } class PreferencesStateNotifier extends Notifier { - late final SharedPreferences _prefs; + SharedPreferences? _prefs; final Completer _ready = Completer(); @override PreferencesState build() { - // Initialize with defaults + // If _prefs was already set by initWithPrefs (for testing), use it + if (_prefs != null) { + return _buildFromPrefs(_prefs!); + } + + // Initialize with defaults for production final defaultState = PreferencesState( theme: 'system', language: _normalizeLanguageTag( @@ -115,11 +120,24 @@ class PreferencesStateNotifier extends Notifier { _ready.complete(); } - // For testing - can be called with mock SharedPreferences + // For testing - can be called with mock SharedPreferences BEFORE build void initWithPrefs(SharedPreferences prefs) { _prefs = prefs; - _load(); - _ready.complete(); + } + + PreferencesState _buildFromPrefs(SharedPreferences prefs) { + final loaded = PreferencesState( + theme: prefs.getString(_kTheme) ?? 'system', + language: _normalizeLanguageTag( + prefs.getString(_kLanguage) ?? + WidgetsBinding.instance.platformDispatcher.locale.toLanguageTag(), + ), + exportDpi: _readDpi(prefs), + theme_color: prefs.getString(_kThemeColor) ?? '#FF2196F3', + ); + // Complete ready immediately for tests + if (!_ready.isCompleted) _ready.complete(); + return loaded; } static Color? _tryParseColor(String? s) { @@ -193,15 +211,16 @@ class PreferencesStateNotifier extends Notifier { } Future _load() async { + if (_prefs == null) return; // Load persisted values (with sane defaults) final loaded = PreferencesState( - theme: _prefs.getString(_kTheme) ?? 'system', + theme: _prefs!.getString(_kTheme) ?? 'system', language: _normalizeLanguageTag( - _prefs.getString(_kLanguage) ?? + _prefs!.getString(_kLanguage) ?? WidgetsBinding.instance.platformDispatcher.locale.toLanguageTag(), ), - exportDpi: _readDpi(_prefs), - theme_color: _prefs.getString(_kThemeColor) ?? '#FF2196F3', + exportDpi: _readDpi(_prefs!), + theme_color: _prefs!.getString(_kThemeColor) ?? '#FF2196F3', ); state = loaded; _ensureValid(); @@ -222,21 +241,22 @@ class PreferencesStateNotifier extends Notifier { } void _ensureValid() { + if (_prefs == null) return; final themeValid = {'light', 'dark', 'system'}; if (!themeValid.contains(state.theme)) { state = state.copyWith(theme: 'system'); - _prefs.setString(_kTheme, 'system'); + _prefs!.setString(_kTheme, 'system'); } final normalized = _normalizeLanguageTag(state.language); if (normalized != state.language) { state = state.copyWith(language: normalized); - _prefs.setString(_kLanguage, normalized); + _prefs!.setString(_kLanguage, normalized); } // Ensure DPI is one of allowed values const allowed = [96.0, 144.0, 200.0, 300.0]; if (!allowed.contains(state.exportDpi)) { state = state.copyWith(exportDpi: 144.0); - _prefs.setDouble(_kExportDpi, 144.0); + _prefs!.setDouble(_kExportDpi, 144.0); } // Ensure theme color is a valid hex or known name; normalize to hex final parsed = _tryParseColor(state.theme_color); @@ -244,12 +264,12 @@ class PreferencesStateNotifier extends Notifier { final fallback = Colors.blue; final hex = _toHex(fallback); state = state.copyWith(theme_color: hex); - _prefs.setString(_kThemeColor, hex); + _prefs!.setString(_kThemeColor, hex); } else { final hex = _toHex(parsed); if (state.theme_color != hex) { state = state.copyWith(theme_color: hex); - _prefs.setString(_kThemeColor, hex); + _prefs!.setString(_kThemeColor, hex); } } } @@ -259,14 +279,14 @@ class PreferencesStateNotifier extends Notifier { if (!valid.contains(theme)) return; state = state.copyWith(theme: theme); await _ensureReady(); - await _prefs.setString(_kTheme, theme); + await _prefs!.setString(_kTheme, theme); } Future setLanguage(String language) async { final normalized = _normalizeLanguageTag(language); state = state.copyWith(language: normalized); await _ensureReady(); - await _prefs.setString(_kLanguage, normalized); + await _prefs!.setString(_kLanguage, normalized); } Future setThemeColor(String themeColor) async { @@ -275,7 +295,7 @@ class PreferencesStateNotifier extends Notifier { final hex = _toHex(c); state = state.copyWith(theme_color: hex); await _ensureReady(); - await _prefs.setString(_kThemeColor, hex); + await _prefs!.setString(_kThemeColor, hex); } Future resetToDefaults() async { @@ -289,11 +309,11 @@ class PreferencesStateNotifier extends Notifier { theme_color: '#FF2196F3', ); await _ensureReady(); - await _prefs.setString(_kTheme, 'system'); - await _prefs.setString(_kLanguage, normalized); - await _prefs.setString(_kPageView, 'continuous'); - await _prefs.setDouble(_kExportDpi, 144.0); - await _prefs.setString(_kThemeColor, '#FF2196F3'); + await _prefs!.setString(_kTheme, 'system'); + await _prefs!.setString(_kLanguage, normalized); + await _prefs!.setString(_kPageView, 'continuous'); + await _prefs!.setDouble(_kExportDpi, 144.0); + await _prefs!.setString(_kThemeColor, '#FF2196F3'); } Future setExportDpi(double dpi) async { @@ -301,7 +321,7 @@ class PreferencesStateNotifier extends Notifier { if (!allowed.contains(dpi)) return; state = state.copyWith(exportDpi: dpi); await _ensureReady(); - await _prefs.setDouble(_kExportDpi, dpi); + await _prefs!.setDouble(_kExportDpi, dpi); } } diff --git a/lib/ui/features/pdf/view_model/pdf_view_model.dart b/lib/ui/features/pdf/view_model/pdf_view_model.dart index f993204..ce09337 100644 --- a/lib/ui/features/pdf/view_model/pdf_view_model.dart +++ b/lib/ui/features/pdf/view_model/pdf_view_model.dart @@ -40,12 +40,12 @@ class PdfViewModel extends Notifier { // Get current document source name for PdfDocumentRefData String get documentSourceName { - // Ensure document version is up to date, but only update if really needed - _updateDocumentVersionIfNeeded(); + // Return the current source name without updating state + // State updates should be done explicitly via updateDocumentVersionIfNeeded() return state.documentVersion.sourceName; } - void _updateDocumentVersionIfNeeded() { + void updateDocumentVersionIfNeeded() { final document = ref.read(documentRepositoryProvider); if (!identical(state.documentVersion.lastBytes, document.pickedPdfBytes)) { state = state.copyWith( diff --git a/lib/ui/features/pdf/view_model/pdf_view_state.dart b/lib/ui/features/pdf/view_model/pdf_view_state.dart index a7abe1c..873ee4b 100644 --- a/lib/ui/features/pdf/view_model/pdf_view_state.dart +++ b/lib/ui/features/pdf/view_model/pdf_view_state.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart' show kDebugMode; import 'package:pdf_signature/ui/features/pdf/view_model/document_version.dart'; import 'package:pdfrx/pdfrx.dart'; @@ -21,12 +22,12 @@ class PdfViewState { }); factory PdfViewState.initial({bool? useMockViewer}) { + // Default to false (no mocking) - tests should explicitly pass true if they want mock viewer + final defaultUseMock = useMockViewer ?? false; return PdfViewState( controller: PdfViewerController(), currentPage: 1, - useMockViewer: - useMockViewer ?? - const bool.fromEnvironment('FLUTTER_TEST', defaultValue: false), + useMockViewer: defaultUseMock, activeRect: null, lockedPlacements: const {}, documentVersion: DocumentVersion.initial(), diff --git a/lib/ui/features/pdf/widgets/pdf_viewer_widget.dart b/lib/ui/features/pdf/widgets/pdf_viewer_widget.dart index 9298181..5b3f941 100644 --- a/lib/ui/features/pdf/widgets/pdf_viewer_widget.dart +++ b/lib/ui/features/pdf/widgets/pdf_viewer_widget.dart @@ -52,6 +52,10 @@ class _PdfViewerWidgetState extends ConsumerState { if (!identical(bytes, _lastBytes)) { _lastBytes = bytes; final viewModel = ref.read(pdfViewModelProvider.notifier); + // Update document version outside of build + Future.microtask(() { + viewModel.updateDocumentVersionIfNeeded(); + }); debugPrint( '[PdfViewerWidget] New PDF bytes detected -> ${viewModel.documentSourceName}', ); diff --git a/lib/ui/features/pdf/widgets/signature_overlay.dart b/lib/ui/features/pdf/widgets/signature_overlay.dart index 2ad7f31..d20667a 100644 --- a/lib/ui/features/pdf/widgets/signature_overlay.dart +++ b/lib/ui/features/pdf/widgets/signature_overlay.dart @@ -118,9 +118,11 @@ class SignatureOverlay extends ConsumerWidget { }, // Keep default handles; you can customize later if needed contentBuilder: (context, boxRect, flip) { - final isLocked = ref - .read(pdfViewModelProvider.notifier) - .isPlacementLocked(page: pageNumber, index: placedIndex); + // Watch the provider state to rebuild when lock state changes + final pdfViewState = ref.watch(pdfViewModelProvider); + final isLocked = pdfViewState.lockedPlacements.contains( + '${pageNumber}_$placedIndex', + ); return DecoratedBox( decoration: BoxDecoration( border: Border.all( diff --git a/test/features/_test_helper.dart b/test/features/_test_helper.dart index 4317a38..4b9173c 100644 --- a/test/features/_test_helper.dart +++ b/test/features/_test_helper.dart @@ -34,6 +34,19 @@ class FakeExportService extends ExportService { } } +class _TestDocumentStateNotifier extends DocumentStateNotifier { + @override + Document build() { + // Initialize with sample document for tests, bypassing the parent build + return Document.initial().copyWith( + loaded: true, + pageCount: 5, + pickedPdfBytes: null, + placementsByPage: >{}, + ); + } +} + Future pumpApp( WidgetTester tester, { Map initialPrefs = const {}, @@ -42,18 +55,16 @@ Future pumpApp( final prefs = await SharedPreferences.getInstance(); final container = ProviderContainer( overrides: [ - preferencesRepositoryProvider.overrideWith( - (ref) => PreferencesStateNotifier(prefs), - ), + preferencesRepositoryProvider.overrideWith(() { + final notifier = PreferencesStateNotifier(); + notifier.initWithPrefs(prefs); + return notifier; + }), documentRepositoryProvider.overrideWith( - (ref) => DocumentStateNotifier()..openSample(), - ), - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), - pdfExportViewModelProvider.overrideWith( - (ref) => PdfExportViewModel(ref, savePathPicker: () async => 'out.pdf'), + () => _TestDocumentStateNotifier(), ), + pdfViewModelProvider.overrideWith(() => PdfViewModel()), + pdfExportViewModelProvider.overrideWith(() => PdfExportViewModel()), ], ); await tester.pumpWidget( diff --git a/test/features/step/_world.dart b/test/features/step/_world.dart index 3210d6c..35e8efe 100644 --- a/test/features/step/_world.dart +++ b/test/features/step/_world.dart @@ -99,8 +99,9 @@ class MockSignatureState { }) : strokes = strokes ?? []; } -class MockSignatureNotifier extends StateNotifier { - MockSignatureNotifier() : super(MockSignatureState()); +class MockSignatureNotifier extends Notifier { + @override + MockSignatureState build() => MockSignatureState(); void setStrokes(List> strokes) { state = MockSignatureState( @@ -174,11 +175,32 @@ class MockSignatureNotifier extends StateNotifier { } final signatureProvider = - StateNotifierProvider( - (ref) => MockSignatureNotifier(), + NotifierProvider( + () => MockSignatureNotifier(), ); -// Mock other providers -final currentRectProvider = StateProvider((ref) => null); -final editingEnabledProvider = StateProvider((ref) => false); -final aspectLockedProvider = StateProvider((ref) => false); +// Mock other providers using NotifierProvider instead of StateProvider +class _CurrentRectNotifier extends Notifier { + @override + Rect? build() => null; +} + +class _EditingEnabledNotifier extends Notifier { + @override + bool build() => false; +} + +class _AspectLockedNotifier extends Notifier { + @override + bool build() => false; +} + +final currentRectProvider = NotifierProvider<_CurrentRectNotifier, Rect?>( + () => _CurrentRectNotifier(), +); +final editingEnabledProvider = NotifierProvider<_EditingEnabledNotifier, bool>( + () => _EditingEnabledNotifier(), +); +final aspectLockedProvider = NotifierProvider<_AspectLockedNotifier, bool>( + () => _AspectLockedNotifier(), +); diff --git a/test/features/step/a_signature_placement_appears_on_the_page_based_on_the_signature_card.dart b/test/features/step/a_signature_placement_appears_on_the_page_based_on_the_signature_card.dart index a6fc6a3..5c7bdd3 100644 --- a/test/features/step/a_signature_placement_appears_on_the_page_based_on_the_signature_card.dart +++ b/test/features/step/a_signature_placement_appears_on_the_page_based_on_the_signature_card.dart @@ -9,8 +9,9 @@ Future aSignaturePlacementAppearsOnThePageBasedOnTheSignatureCard( ) async { final container = TestWorld.container!; final pdf = container.read(documentRepositoryProvider); - final page = container.read(pdfViewModelProvider); - final placements = pdf.placementsByPage[page] ?? const []; + final pdfView = container.read(pdfViewModelProvider); + final currentPage = pdfView.currentPage; + final placements = pdf.placementsByPage[currentPage] ?? const []; expect( placements.isNotEmpty, true, diff --git a/test/features/step/only_the_selected_signature_placement_is_removed.dart b/test/features/step/only_the_selected_signature_placement_is_removed.dart index 46e5c03..c54a963 100644 --- a/test/features/step/only_the_selected_signature_placement_is_removed.dart +++ b/test/features/step/only_the_selected_signature_placement_is_removed.dart @@ -10,7 +10,8 @@ Future onlyTheSelectedSignaturePlacementIsRemoved( ) async { final container = TestWorld.container ?? ProviderContainer(); final pdf = container.read(documentRepositoryProvider); - final page = container.read(pdfViewModelProvider); - final placements = pdf.placementsByPage[page] ?? const []; + final pdfView = container.read(pdfViewModelProvider); + final currentPage = pdfView.currentPage; + final placements = pdf.placementsByPage[currentPage] ?? const []; expect(placements.length, 2); // Started with 3, removed 1, should have 2 } diff --git a/test/features/step/the_app_launches.dart b/test/features/step/the_app_launches.dart index 2d67810..5cc5576 100644 --- a/test/features/step/the_app_launches.dart +++ b/test/features/step/the_app_launches.dart @@ -32,38 +32,19 @@ Future theAppLaunches(WidgetTester tester) async { final container = ProviderContainer( overrides: [ - preferencesRepositoryProvider.overrideWith( - (ref) => PreferencesStateNotifier(prefs), - ), - documentRepositoryProvider.overrideWith( - (ref) => DocumentStateNotifier()..openSample(), - ), - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), + preferencesRepositoryProvider.overrideWith(() { + final notifier = PreferencesStateNotifier(); + notifier.initWithPrefs(prefs); + return notifier; + }), + documentRepositoryProvider.overrideWith(() => DocumentStateNotifier()), + pdfViewModelProvider.overrideWith(() => PdfViewModel()), // Bridge: automatically mirror assets into signature cards so legacy // feature steps that expect SignatureCard widgets keep working even // though the production UI currently only stores raw assets. - signatureCardRepositoryProvider.overrideWith((ref) { - final notifier = _BridgedSignatureCardStateNotifier(); - ref.listen>(signatureAssetRepositoryProvider, ( - prev, - next, - ) { - for (final asset in next) { - if (!notifier.state.any((c) => identical(c.asset, asset))) { - notifier.add(SignatureCard(asset: asset, rotationDeg: 0.0)); - } - } - // Remove cards whose assets were removed - final remaining = - notifier.state.where((c) => next.contains(c.asset)).toList(); - if (remaining.length != notifier.state.length) { - notifier.setAll(remaining); - } - }); - return notifier; - }), + signatureCardRepositoryProvider.overrideWith( + () => _BridgedSignatureCardStateNotifier(), + ), ], ); TestWorld.container = container; diff --git a/test/features/step/the_other_signature_placements_remain_unchanged.dart b/test/features/step/the_other_signature_placements_remain_unchanged.dart index bd87fbc..f95f673 100644 --- a/test/features/step/the_other_signature_placements_remain_unchanged.dart +++ b/test/features/step/the_other_signature_placements_remain_unchanged.dart @@ -9,7 +9,8 @@ Future theOtherSignaturePlacementsRemainUnchanged( ) async { final container = TestWorld.container!; final pdf = container.read(documentRepositoryProvider); - final page = container.read(pdfViewModelProvider); - final placements = pdf.placementsByPage[page] ?? const []; + final pdfView = container.read(pdfViewModelProvider); + final currentPage = pdfView.currentPage; + final placements = pdf.placementsByPage[currentPage] ?? const []; expect(placements.length, 2); // Should have 2 remaining after deleting 1 } diff --git a/test/features/step/the_user_opens_a_different_document_with_pages.dart b/test/features/step/the_user_opens_a_different_document_with_pages.dart index 1c5e752..3dab1a0 100644 --- a/test/features/step/the_user_opens_a_different_document_with_pages.dart +++ b/test/features/step/the_user_opens_a_different_document_with_pages.dart @@ -38,6 +38,6 @@ Future theUserOpensADifferentDocumentWithPages( } } // Moving to a new document should show page 1. - container.read(pdfViewModelProvider).currentPage = 1; + container.read(pdfViewModelProvider.notifier).jumpToPage(1); await tester.pumpAndSettle(); } diff --git a/test/widget/export_flow_test.dart b/test/widget/export_flow_test.dart index 5b858d1..dce4e11 100644 --- a/test/widget/export_flow_test.dart +++ b/test/widget/export_flow_test.dart @@ -13,14 +13,17 @@ import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart'; import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; +import 'package:pdf_signature/domain/models/model.dart'; // A fake export VM that always reports success, so this widget test doesn't // depend on PDF validity or platform specifics. bool exported = false; class _FakePdfExportViewModel extends PdfExportViewModel { - _FakePdfExportViewModel(Ref ref) - : super(ref, savePathPicker: () async => 'C:/tmp/output.pdf'); + @override + Future pickSavePathWithSuggestedName(String suggestedName) async { + return '/fake/path/output.pdf'; // Return a fake path + } @override Future exportToPath({ @@ -34,6 +37,18 @@ class _FakePdfExportViewModel extends PdfExportViewModel { } } +class _TestDocumentStateNotifier extends DocumentStateNotifier { + @override + Document build() { + return Document.initial().copyWith( + loaded: true, + pageCount: 5, + pickedPdfBytes: Uint8List(0), + placementsByPage: >{}, + ); + } +} + void main() { testWidgets('Save uses file selector (via provider) and injected exporter', ( tester, @@ -43,22 +58,17 @@ void main() { await tester.pumpWidget( ProviderScope( overrides: [ - preferencesRepositoryProvider.overrideWith( - (ref) => PreferencesStateNotifier(prefs), - ), + preferencesRepositoryProvider.overrideWith(() { + final notifier = PreferencesStateNotifier(); + notifier.initWithPrefs(prefs); + return notifier; + }), documentRepositoryProvider.overrideWith( - (ref) => - DocumentStateNotifier()..openDocument( - bytes: Uint8List(0), - pageCount: 5, - knownPageCount: true, - ), - ), - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), + () => _TestDocumentStateNotifier(), ), + pdfViewModelProvider.overrideWith(() => PdfViewModel()), pdfExportViewModelProvider.overrideWith( - (ref) => _FakePdfExportViewModel(ref), + () => _FakePdfExportViewModel(), ), ], child: MaterialApp( diff --git a/test/widget/helpers.dart b/test/widget/helpers.dart index d8c9fa3..f129241 100644 --- a/test/widget/helpers.dart +++ b/test/widget/helpers.dart @@ -7,28 +7,102 @@ import 'package:image/image.dart' as img; import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/pdf_export_view_model.dart'; import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/data/repositories/signature_asset_repository.dart'; import 'package:pdf_signature/data/repositories/signature_card_repository.dart'; import 'package:pdf_signature/domain/models/signature_asset.dart'; +import 'package:pdf_signature/domain/models/model.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; // preferences_providers.dart no longer exports pageViewModeProvider +// Test helper classes +class TestPdfViewModel extends PdfViewModel { + @override + PdfViewState build() { + return PdfViewState.initial(useMockViewer: true); + } +} + +class TestDocumentStateNotifier extends DocumentStateNotifier { + @override + Document build() { + // Initialize with sample document for tests, bypassing the parent build + return Document.initial().copyWith( + loaded: true, + pageCount: 5, + pickedPdfBytes: null, + placementsByPage: >{}, + ); + } +} + +class TestDocumentStateNotifierWithPlacements extends DocumentStateNotifier { + final Uint8List pdfBytes; + final List signatureBytes; + + TestDocumentStateNotifierWithPlacements(this.pdfBytes, this.signatureBytes); + + @override + Document build() { + final image = img.decodeImage(Uint8List.fromList(signatureBytes))!; + final asset = SignatureAsset(sigImage: image); + + return Document.initial().copyWith( + loaded: true, + pageCount: 5, + pickedPdfBytes: pdfBytes, + placementsByPage: { + 1: [ + SignaturePlacement( + rect: const Rect.fromLTWH(0.1, 0.1, 0.3, 0.2), + asset: asset, + ), + ], + }, + ); + } +} + +// Test notifier for SignatureCardRepository with pre-initialized card +class TestSignatureCardStateNotifier extends SignatureCardStateNotifier { + final List signatureBytes; + + TestSignatureCardStateNotifier(this.signatureBytes); + @override + List build() { + // Initialize with a card already added + final image = img.decodeImage(Uint8List.fromList(signatureBytes))!; + final asset = SignatureAsset(sigImage: image, name: 'test'); + + return [SignatureCard(asset: asset, rotationDeg: 0.0)]; + } +} + +// Test notifier for SignatureAssetRepository with pre-loaded asset +class TestSignatureAssetRepository extends SignatureAssetRepository { + final List signatureBytes; + + TestSignatureAssetRepository(this.signatureBytes); + @override + List build() { + // Initialize with an asset already added + final image = img.decodeImage(Uint8List.fromList(signatureBytes))!; + return [SignatureAsset(sigImage: image, name: 'test')]; + } +} + Future pumpWithOpenPdf(WidgetTester tester) async { await tester.pumpWidget( ProviderScope( overrides: [ documentRepositoryProvider.overrideWith( - (ref) => DocumentStateNotifier()..openSample(), - ), - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), - pdfExportViewModelProvider.overrideWith( - (ref) => PdfExportViewModel(ref), + () => TestDocumentStateNotifier(), ), + pdfViewModelProvider.overrideWith(() => TestPdfViewModel()), + pdfExportViewModelProvider.overrideWith(() => PdfExportViewModel()), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, @@ -370,42 +444,18 @@ Future pumpWithOpenPdfAndSig(WidgetTester tester) async { await tester.pumpWidget( ProviderScope( overrides: [ - documentRepositoryProvider.overrideWith((ref) { - final notifier = DocumentStateNotifier()..openSample(); - // Set PDF bytes so the viewer can display something - notifier.state = notifier.state.copyWith(pickedPdfBytes: pdfBytes); - // Add a signature placement on page 1 - notifier.addPlacement( - page: 1, - rect: const Rect.fromLTWH(0.1, 0.1, 0.3, 0.2), - asset: SignatureAsset( - sigImage: img.decodeImage(Uint8List.fromList(bytes))!, - ), - ); - return notifier; - }), - signatureAssetRepositoryProvider.overrideWith((ref) { - final repo = SignatureAssetRepository(); - final image = img.decodeImage(Uint8List.fromList(bytes))!; - repo.addImage(image, name: 'test'); - return repo; - }), - signatureCardRepositoryProvider.overrideWith((ref) { - final cardRepo = SignatureCardStateNotifier(); - final asset = SignatureAsset( - sigImage: img.decodeImage(Uint8List.fromList(bytes))!, - name: 'test', - ); - cardRepo.addWithAsset(asset, 0.0); - return cardRepo; - }), + documentRepositoryProvider.overrideWith( + () => TestDocumentStateNotifierWithPlacements(pdfBytes, bytes), + ), + signatureAssetRepositoryProvider.overrideWith( + () => TestSignatureAssetRepository(bytes), + ), + signatureCardRepositoryProvider.overrideWith( + () => TestSignatureCardStateNotifier(bytes), + ), // In new model, interactive overlay not implemented; keep library empty - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), - pdfExportViewModelProvider.overrideWith( - (ref) => PdfExportViewModel(ref), - ), + pdfViewModelProvider.overrideWith(() => TestPdfViewModel()), + pdfExportViewModelProvider.overrideWith(() => PdfExportViewModel()), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, diff --git a/test/widget/pdf_navigation_widget_test.dart b/test/widget/pdf_navigation_widget_test.dart index 712302e..e792842 100644 --- a/test/widget/pdf_navigation_widget_test.dart +++ b/test/widget/pdf_navigation_widget_test.dart @@ -5,15 +5,24 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart'; import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/domain/models/model.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; class _TestPdfController extends DocumentStateNotifier { - _TestPdfController() : super() { + @override + Document build() { // Start with a loaded multi-page doc, page 1 of 5 - state = Document.initial().copyWith(loaded: true, pageCount: 5); + return Document.initial().copyWith(loaded: true, pageCount: 5); + } +} + +class _TestPdfViewModel extends PdfViewModel { + @override + PdfViewState build() { + return PdfViewState.initial(useMockViewer: true); } } @@ -24,12 +33,8 @@ void main() { await tester.pumpWidget( ProviderScope( overrides: [ - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), - documentRepositoryProvider.overrideWith( - (ref) => _TestPdfController(), - ), + pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()), + documentRepositoryProvider.overrideWith(() => _TestPdfController()), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, diff --git a/test/widget/pdf_page_area_early_jump_test.dart b/test/widget/pdf_page_area_early_jump_test.dart index 9ead012..9355c3b 100644 --- a/test/widget/pdf_page_area_early_jump_test.dart +++ b/test/widget/pdf_page_area_early_jump_test.dart @@ -7,13 +7,22 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart'; import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; import 'package:pdf_signature/domain/models/model.dart'; class _TestPdfController extends DocumentStateNotifier { - _TestPdfController() : super() { - state = Document.initial().copyWith(loaded: true, pageCount: 6); + @override + Document build() { + return Document.initial().copyWith(loaded: true, pageCount: 6); + } +} + +class _TestPdfViewModel extends PdfViewModel { + @override + PdfViewState build() { + return PdfViewState.initial(useMockViewer: true); } } @@ -26,10 +35,8 @@ void main() { await tester.pumpWidget( ProviderScope( overrides: [ - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), - documentRepositoryProvider.overrideWith((ref) => ctrl), + pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()), + documentRepositoryProvider.overrideWith(() => ctrl), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, diff --git a/test/widget/pdf_page_area_jump_test.dart b/test/widget/pdf_page_area_jump_test.dart index c482875..47b2eaa 100644 --- a/test/widget/pdf_page_area_jump_test.dart +++ b/test/widget/pdf_page_area_jump_test.dart @@ -7,13 +7,22 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart'; import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; import 'package:pdf_signature/domain/models/model.dart'; class _TestPdfController extends DocumentStateNotifier { - _TestPdfController() : super() { - state = Document.initial().copyWith(loaded: true, pageCount: 6); + @override + Document build() { + return Document.initial().copyWith(loaded: true, pageCount: 6); + } +} + +class _TestPdfViewModel extends PdfViewModel { + @override + PdfViewState build() { + return PdfViewState.initial(useMockViewer: true); } } @@ -26,11 +35,9 @@ void main() { await tester.pumpWidget( ProviderScope( overrides: [ - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), + pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()), // Continuous mode is always-on; no page view override needed - documentRepositoryProvider.overrideWith((ref) => ctrl), + documentRepositoryProvider.overrideWith(() => ctrl), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, diff --git a/test/widget/pdf_page_area_test.dart b/test/widget/pdf_page_area_test.dart index 0135669..926f8f5 100644 --- a/test/widget/pdf_page_area_test.dart +++ b/test/widget/pdf_page_area_test.dart @@ -7,14 +7,24 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart'; import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart'; import 'package:pdfrx/pdfrx.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; import 'package:pdf_signature/domain/models/model.dart'; +import 'helpers.dart'; class _TestPdfController extends DocumentStateNotifier { - _TestPdfController() : super() { - state = Document.initial().copyWith(loaded: true, pageCount: 6); + @override + Document build() { + return Document.initial().copyWith(loaded: true, pageCount: 6); + } +} + +class _TestPdfViewModel extends PdfViewModel { + @override + PdfViewState build() { + return PdfViewState.initial(useMockViewer: true); } } @@ -25,12 +35,8 @@ void main() { await tester.pumpWidget( ProviderScope( overrides: [ - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), - documentRepositoryProvider.overrideWith( - (ref) => _TestPdfController(), - ), + pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()), + documentRepositoryProvider.overrideWith(() => _TestPdfController()), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, @@ -65,11 +71,9 @@ void main() { // Use a persistent container across rebuilds final container = ProviderContainer( overrides: [ - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), - ), + pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()), documentRepositoryProvider.overrideWith( - (ref) => DocumentStateNotifier()..openSample(), + () => TestDocumentStateNotifier(), ), ], ); diff --git a/test/widget/signature_overlay_test.dart b/test/widget/signature_overlay_test.dart index c24b049..5ef11f4 100644 --- a/test/widget/signature_overlay_test.dart +++ b/test/widget/signature_overlay_test.dart @@ -12,6 +12,8 @@ import 'package:pdf_signature/data/repositories/document_repository.dart'; import 'package:pdf_signature/domain/models/model.dart'; import 'package:pdf_signature/l10n/app_localizations.dart'; +import 'helpers.dart'; + void main() { late ProviderContainer container; late SignatureAsset testAsset; @@ -37,11 +39,9 @@ void main() { container = ProviderContainer( overrides: [ documentRepositoryProvider.overrideWith( - (ref) => DocumentStateNotifier()..openSample(), - ), - pdfViewModelProvider.overrideWith( - (ref) => PdfViewModel(ref, useMockViewer: true), + () => TestDocumentStateNotifier(), ), + pdfViewModelProvider.overrideWith(() => PdfViewModel()), ], ); });