import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:relationship_saver/core/config/app_theme.dart'; import 'package:relationship_saver/features/local/local_repository.dart'; import 'package:relationship_saver/features/local/storage/local_data_store_in_memory.dart'; import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart'; import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart'; import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart'; import 'package:relationship_saver/features/sync/sync_queue_repository.dart'; import 'package:relationship_saver/features/sync/sync_view.dart'; import 'package:relationship_saver/integrations/backend/models/backend_models.dart'; void main() { testWidgets( 'rejected person mutation can be repaired directly from Sync view', (WidgetTester tester) async { final ProviderContainer container = ProviderContainer( overrides: [ localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()), syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()), ], ); addTearDown(container.dispose); final localBefore = await container.read(localRepositoryProvider.future); final person = localBefore.people.first; final ChangeEnvelope rejectedChange = ChangeEnvelope( schemaVersion: 1, entityType: 'person', entityId: person.id, op: ChangeOperation.upsert, modifiedAt: DateTime(2026, 2, 15, 12).toUtc(), clientMutationId: 'cm-repair-1', payload: { 'name': person.name, 'relationship': person.relationship, 'notes': person.notes, 'tags': person.tags, }, ); final syncNotifier = container.read(syncQueueRepositoryProvider.notifier); await syncNotifier.enqueue(rejectedChange); await syncNotifier.applyPushResult( const SyncPushResult( cursor: 'cursor-1', rejected: [ MutationRejection( clientMutationId: 'cm-repair-1', code: 'VALIDATION_FAILED', message: 'Bad payload', ), ], ), ); final syncState = await container.read(syncQueueRepositoryProvider.future); expect(syncState.lastRejected.length, 1); await tester.pumpWidget( UncontrolledProviderScope( container: container, child: MaterialApp(theme: AppTheme.light(), home: const SyncView()), ), ); await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.scrollUntilVisible( find.text('Rejected Changes'), 240, scrollable: find.byType(Scrollable).first, ); expect(find.text('Rejected Changes'), findsOneWidget); await tester.scrollUntilVisible( find.widgetWithText(TextButton, 'Open Related Screen'), 120, scrollable: find.byType(Scrollable).first, ); final Finder openRelatedScreenButton = find.widgetWithText( TextButton, 'Open Related Screen', ); expect(openRelatedScreenButton, findsOneWidget); await tester.ensureVisible(openRelatedScreenButton); await tester.pumpAndSettle(const Duration(milliseconds: 200)); await tester.tap(openRelatedScreenButton, warnIfMissed: false); await tester.pumpAndSettle(const Duration(milliseconds: 500)); expect(find.textContaining('Focus: person:'), findsOneWidget); await tester.enterText(find.byType(TextField).first, 'Renamed Person'); await tester.tap(find.widgetWithText(FilledButton, 'Save Changes')); await tester.pumpAndSettle(const Duration(milliseconds: 500)); final localAfter = await container.read(localRepositoryProvider.future); final updated = localAfter.people.firstWhere( (item) => item.id == person.id, ); expect(updated.name, 'Renamed Person'); }, ); }