import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:kooltap/l10n/app_localizations.dart'; import 'package:kooltap/models/bar_tab.dart'; import 'package:kooltap/utils/name_index.dart'; import 'package:kooltap/views/bar/tab_panel.dart'; const _names = [ 'Zoë', 'anna', 'Émile', 'Bram', 'Mieke', 'Marc', 'Ward', 'Tom', 'Sofie', // 'Lotte', 'Koen', 'Jan', 'Inge', 'Hanne', 'Greet', 'Frank', 'Dirk', 'Chris', 'Nele', 'Olaf', 'Pieter', 'Rik', 'Vera', 'Yves', '2de tafel', 'Eva', ]; void main() { group('name index', () { test('folds case and accents into the index letter', () { expect(indexLetterOf('émile'), 'E'); expect(indexLetterOf('Zoë'), 'Z'); expect(indexLetterOf(' anna'), 'A'); expect(indexLetterOf('2de tafel'), '#'); expect(indexLetterOf(''), '#'); }); test('sorts A–Z regardless of case and accents, # last', () { final sorted = ['Zoë', 'émile', 'Eva', 'anna', '2de tafel', 'Bram'] ..sort(compareByIndex); expect(sorted, ['anna', 'Bram', 'émile', 'Eva', 'Zoë', '2de tafel']); }); }); group('TabPanel letter index', () { final tabs = [ for (final (index, name) in _names.indexed) BarTab( id: 'tab-$index', customerName: name, openedAt: DateTime(2026, 10, 11, 12, index), items: const [], ), ]; Future pumpPanel( WidgetTester tester, { bool showSearch = false, }) async { tester.view.physicalSize = const Size(500, 800); tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); await tester.pumpWidget( MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: TabPanel( tabs: tabs, selectedTab: null, selectedTabId: null, stockByProductId: const {}, showSearch: showSearch, onTabSelected: (_) {}, onItemQuantityChanged: (_, _) async {}, onCloseTabPressed: () {}, onTabEdited: (_) async {}, onTabDeleted: (_) async {}, ), ), ), ); } String firstVisibleName(WidgetTester tester) { final list = tester.getRect(find.byType(OpenTabsList)); final visible = _names.where((name) { final finder = find.text(name); if (finder.evaluate().isEmpty) return false; final rect = tester.getRect(finder); return rect.top >= list.top && rect.bottom <= list.bottom; }).toList(); return visible.reduce( (a, b) => tester.getRect(find.text(a)).top < tester.getRect(find.text(b)).top ? a : b, ); } Future tapLetter(WidgetTester tester, String letter) async { await tester.tap( find.descendant( of: find.byWidgetPredicate( (widget) => widget.runtimeType.toString() == '_LetterIndexBar', ), matching: find.text(letter), ), ); await tester.pumpAndSettle(); } testWidgets('lists the tabs alphabetically', (tester) async { await pumpPanel(tester); expect(firstVisibleName(tester), 'anna'); }); testWidgets('tapping a letter scrolls to its first name', (tester) async { await pumpPanel(tester); await tapLetter(tester, 'M'); expect(firstVisibleName(tester), 'Marc'); await tapLetter(tester, 'E'); expect(firstVisibleName(tester), 'Émile'); }); testWidgets('shows the search bar only when asked', (tester) async { await pumpPanel(tester); expect(find.byType(TextField), findsNothing); await pumpPanel(tester, showSearch: true); expect(find.byType(TextField), findsOneWidget); }); testWidgets('closing the search clears the filter', (tester) async { await pumpPanel(tester, showSearch: true); await tester.enterText(find.byType(TextField), 'Marc'); await tester.pump(); expect(find.text('anna'), findsNothing); await pumpPanel(tester); expect(find.text('anna'), findsOneWidget); }); testWidgets('a letter without names goes to the next one', (tester) async { await pumpPanel(tester); await tapLetter(tester, 'Q'); expect(firstVisibleName(tester), 'Rik'); }); }); }