fix(search): fix history overlay flicker and clear/delete behavior
This commit is contained in:
1 parent
20d5d4d694
commit
28f1dfb1b0
4 files changed
+529
-169
No files matched your search
@@ -0,0 +1,164 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:frontend/ui/shared/inputs/app_search_bar.dart';
|
||||
import 'package:frontend/ui/providers/search_history_provider.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues({
|
||||
'app_search_history': '["test item 1", "test item 2"]',
|
||||
});
|
||||
});
|
||||
|
||||
test('SearchHistoryNotifier loads, adds, removes, and clears history', () async {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
expect(container.read(searchHistoryProvider), isEmpty);
|
||||
|
||||
await Future<void>.delayed(const Duration(milliseconds: 100));
|
||||
final history = container.read(searchHistoryProvider);
|
||||
expect(history, containsAll(['test item 1', 'test item 2']));
|
||||
|
||||
await container.read(searchHistoryProvider.notifier).addSearch('new item');
|
||||
expect(container.read(searchHistoryProvider).first, equals('new item'));
|
||||
|
||||
await container.read(searchHistoryProvider.notifier).removeSearch('test item 1');
|
||||
expect(container.read(searchHistoryProvider), isNot(contains('test item 1')));
|
||||
|
||||
await container.read(searchHistoryProvider.notifier).clearHistory();
|
||||
expect(container.read(searchHistoryProvider), isEmpty);
|
||||
});
|
||||
|
||||
testWidgets('AppSearchBar displays history overlay on focus and supports clear all', (tester) async {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
container.read(searchHistoryProvider);
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.pumpWidget(
|
||||
UncontrolledProviderScope(
|
||||
container: container,
|
||||
child: const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: AppSearchBar(
|
||||
hint: 'Search test...',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
// Tap search bar to focus
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
|
||||
// Verify history overlay is displayed
|
||||
expect(find.text('Recent Searches'), findsOneWidget);
|
||||
expect(find.text('test item 1'), findsOneWidget);
|
||||
expect(find.text('test item 2'), findsOneWidget);
|
||||
expect(find.text('Clear all'), findsOneWidget);
|
||||
|
||||
// Tap Clear all
|
||||
await tester.tap(find.text('Clear all'));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
|
||||
// History is now cleared and overlay closes
|
||||
expect(container.read(searchHistoryProvider), isEmpty);
|
||||
expect(find.text('Recent Searches'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('AppSearchBar individual item deletion removes item and keeps overlay open', (tester) async {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
container.read(searchHistoryProvider);
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.pumpWidget(
|
||||
UncontrolledProviderScope(
|
||||
container: container,
|
||||
child: const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: AppSearchBar(
|
||||
hint: 'Search test...',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
// Open overlay
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
|
||||
expect(find.text('test item 1'), findsOneWidget);
|
||||
expect(find.text('test item 2'), findsOneWidget);
|
||||
|
||||
// Find the close buttons on history items
|
||||
final closeIcons = find.byIcon(Icons.close_rounded);
|
||||
expect(closeIcons, findsWidgets);
|
||||
|
||||
// Tap the first history item close button
|
||||
await tester.tap(closeIcons.first);
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
|
||||
// Item 1 was removed, Item 2 remains, overlay remains open
|
||||
expect(container.read(searchHistoryProvider), isNot(contains('test item 1')));
|
||||
expect(container.read(searchHistoryProvider), contains('test item 2'));
|
||||
expect(find.text('Recent Searches'), findsOneWidget);
|
||||
expect(find.text('test item 2'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('AppSearchBar pressing escape closes overlay', (tester) async {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
container.read(searchHistoryProvider);
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.pumpWidget(
|
||||
UncontrolledProviderScope(
|
||||
container: container,
|
||||
child: const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: AppSearchBar(
|
||||
hint: 'Search test...',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
// Focus to open overlay
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
expect(find.text('Recent Searches'), findsOneWidget);
|
||||
|
||||
// Press Escape
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
|
||||
// Overlay is dismissed
|
||||
expect(find.text('Recent Searches'), findsNothing);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user