Add people quick-capture dialog regression test
This commit is contained in:
@@ -7,6 +7,25 @@ Updated: 2026-02-22
|
||||
- After every sensible code/documentation change set, create a git commit as
|
||||
the last step so the next agent session can pick up from clean checkpoints.
|
||||
|
||||
## Latest Milestone (2026-02-22): Quick-Capture Dialog Regression Test (People)
|
||||
|
||||
Added explicit widget-test coverage so controller lifecycle issues in quick
|
||||
capture dialogs are caught automatically in CI/local runs.
|
||||
|
||||
- `test/features/people/people_quick_capture_dialog_test.dart` (new)
|
||||
- mounts `PeopleView` in mobile layout
|
||||
- opens profile-context `Capture` quick action dialog
|
||||
- exercises `Cancel` path and pumps through dismissal frames
|
||||
- reopens dialog, saves a capture, and pumps through dismissal frames
|
||||
- asserts:
|
||||
- no framework exceptions surfaced (`tester.takeException() == null`)
|
||||
- local moments count increases after save
|
||||
- specifically protects against the disposed `TextEditingController` race
|
||||
|
||||
- Validation
|
||||
- `flutter analyze` -> pass
|
||||
- `flutter test` -> pass
|
||||
|
||||
## Latest Milestone (2026-02-22): Quick-Capture Dialog Controller Lifecycle Fix
|
||||
|
||||
Fixed a runtime crash when creating captures/notes from profile-context quick
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
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_models.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/people/people_view.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:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues(<String, Object>{});
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'people quick capture dialog can cancel and save without controller lifecycle errors',
|
||||
(WidgetTester tester) async {
|
||||
await tester.binding.setSurfaceSize(const Size(390, 844));
|
||||
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||
|
||||
final ProviderContainer container = ProviderContainer(
|
||||
overrides: [
|
||||
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
],
|
||||
);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final LocalDataState initial = await container.read(
|
||||
localRepositoryProvider.future,
|
||||
);
|
||||
final int beforeMomentsCount = initial.moments.length;
|
||||
|
||||
await tester.pumpWidget(
|
||||
UncontrolledProviderScope(
|
||||
container: container,
|
||||
child: MaterialApp(
|
||||
theme: AppTheme.light(),
|
||||
home: const Scaffold(body: PeopleView()),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
|
||||
expect(find.text('People'), findsWidgets);
|
||||
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Capture').first);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 250));
|
||||
|
||||
expect(find.text('Add Capture'), findsOneWidget);
|
||||
expect(find.widgetWithText(TextButton, 'Cancel'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.widgetWithText(TextButton, 'Cancel'));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 250));
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 250));
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Capture').first);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 250));
|
||||
|
||||
expect(find.text('Add Capture'), findsOneWidget);
|
||||
await tester.enterText(
|
||||
find.descendant(
|
||||
of: find.byType(AlertDialog),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
'Captured from profile quick action for regression test',
|
||||
);
|
||||
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Save'));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 250));
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 400));
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
final LocalDataState after = await container.read(
|
||||
localRepositoryProvider.future,
|
||||
);
|
||||
expect(after.moments.length, beforeMomentsCount + 1);
|
||||
expect(
|
||||
after.moments.first.summary,
|
||||
contains('Captured from profile quick action'),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user