import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:motorcycle_dash/core/theme/theme_extensions.dart'; import 'package:motorcycle_dash/features/social/clubs/club_detail_screen.dart'; import 'package:motorcycle_dash/features/social/clubs/widgets/officer_badge.dart'; import 'package:motorcycle_dash/services/auth/auth_providers.dart'; import 'package:motorcycle_dash/services/auth/auth_user.dart'; import 'package:motorcycle_dash/services/clubs/club_models.dart'; import 'package:motorcycle_dash/services/clubs/club_providers.dart'; import 'package:motorcycle_dash/services/clubs/club_service.dart'; class MockClubServiceForRoster extends ClubService { String? updatedRank; String? updatedTargetUid; @override Future updateMemberRoleAndRank( String clubId, String targetUid, { ClubRole? newRole, String? newDisplayRank, String? callerUid, }) async { updatedTargetUid = targetUid; updatedRank = newDisplayRank; } } void main() { group('MOB-24: Club Wall & Member Roster Interactive Features', () { const testUser = AuthUser(uid: 'rider_test_01', isAnonymous: false); final testClub = Club( id: 'club_iron_riders', name: 'Iron Ridge MC', slug: 'iron-ridge', description: 'Mountain pass endurance club', ownerUid: 'owner_marcus', memberCount: 4, visibility: ClubVisibility.public, admissionPolicy: ClubAdmissionPolicy.open, createdAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); final activeMember = ClubMember( uid: 'rider_test_01', clubId: 'club_iron_riders', status: ClubMemberStatus.active, role: ClubRole.admin, displayRank: 'Road Captain', updatedAt: DateTime(2026, 1, 1), ); final membersRoster = [ ClubMember( uid: 'owner_marcus', clubId: 'club_iron_riders', status: ClubMemberStatus.active, role: ClubRole.owner, displayRank: 'President', updatedAt: DateTime(2026, 1, 1), ), activeMember, ClubMember( uid: 'rider_samir', clubId: 'club_iron_riders', status: ClubMemberStatus.active, role: ClubRole.member, displayRank: 'Tail Gunner', updatedAt: DateTime(2026, 1, 1), ), ClubMember( uid: 'rider_dave', clubId: 'club_iron_riders', status: ClubMemberStatus.active, role: ClubRole.member, displayRank: 'Full Member', updatedAt: DateTime(2026, 1, 1), ), ]; testWidgets('renders tab bar with Overview, Club Wall, and Roster', (tester) async { await tester.pumpWidget( ProviderScope( overrides: [ currentUserProvider.overrideWith((ref) => testUser), clubDetailProvider('club_iron_riders').overrideWith((ref) => Stream.value(testClub)), currentMemberProvider('club_iron_riders').overrideWith((ref) => Stream.value(activeMember)), clubMembersProvider('club_iron_riders').overrideWith((ref) => Stream.value(membersRoster)), ], child: MaterialApp( theme: ThemeData.dark().copyWith( extensions: [MotorSignalThemeColors.dark], ), home: const ClubDetailScreen(clubId: 'club_iron_riders'), ), ), ); await tester.pumpAndSettle(); expect(find.text('OVERVIEW'), findsOneWidget); expect(find.text('CLUB WALL'), findsOneWidget); expect(find.text('ROSTER'), findsOneWidget); // Verify Overview elements exist expect(find.text('About the Club'), findsOneWidget); expect(find.text('CLUB RIDES'), findsOneWidget); }); testWidgets('switches to Club Wall tab and displays seeded discussion feed', (tester) async { await tester.pumpWidget( ProviderScope( overrides: [ currentUserProvider.overrideWith((ref) => testUser), clubDetailProvider('club_iron_riders').overrideWith((ref) => Stream.value(testClub)), currentMemberProvider('club_iron_riders').overrideWith((ref) => Stream.value(activeMember)), clubMembersProvider('club_iron_riders').overrideWith((ref) => Stream.value(membersRoster)), ], child: MaterialApp( theme: ThemeData.dark().copyWith( extensions: [MotorSignalThemeColors.dark], ), home: const ClubDetailScreen(clubId: 'club_iron_riders'), ), ), ); await tester.pumpAndSettle(); // Tap Club Wall tab await tester.tap(find.text('CLUB WALL')); await tester.pumpAndSettle(); // Verify Pinned Announcement expect(find.text('PINNED LEADERSHIP ANNOUNCEMENT'), findsOneWidget); expect(find.textContaining('SATURDAY RIDE BRIEFING'), findsOneWidget); // Verify discussion posts & fist bump counters expect(find.text('Marcus Vance'), findsOneWidget); expect(find.text('Samir Chen'), findsOneWidget); expect(find.textContaining('Fist Bumps'), findsWidgets); }); testWidgets('switches to Member Roster tab, filters members, and checks officer badges', (tester) async { await tester.pumpWidget( ProviderScope( overrides: [ currentUserProvider.overrideWith((ref) => testUser), clubDetailProvider('club_iron_riders').overrideWith((ref) => Stream.value(testClub)), currentMemberProvider('club_iron_riders').overrideWith((ref) => Stream.value(activeMember)), clubMembersProvider('club_iron_riders').overrideWith((ref) => Stream.value(membersRoster)), ], child: MaterialApp( theme: ThemeData.dark().copyWith( extensions: [MotorSignalThemeColors.dark], ), home: const ClubDetailScreen(clubId: 'club_iron_riders'), ), ), ); await tester.pumpAndSettle(); // Tap Roster tab await tester.tap(find.text('ROSTER')); await tester.pumpAndSettle(); // Verify filter chips expect(find.text('All Members'), findsOneWidget); expect(find.text('Executive Officers'), findsOneWidget); expect(find.text('Road Captains & Sweeps'), findsOneWidget); // Verify members & badges expect(find.text('President'), findsWidgets); expect(find.text('Road Captain (You)'), findsOneWidget); expect(find.text('Tail Gunner'), findsWidgets); }); testWidgets('tests OfficerBadge rendering across officer ranks', (tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.dark().copyWith( extensions: [MotorSignalThemeColors.dark], ), home: const Scaffold( body: Column( children: [ OfficerBadge(rank: 'President'), OfficerBadge(rank: 'Road Captain'), OfficerBadge(rank: 'Tail Gunner'), OfficerBadge(rank: 'Road Marshal'), OfficerBadge(rank: 'Full Member'), ], ), ), ), ); await tester.pumpAndSettle(); expect(find.text('PRESIDENT'), findsOneWidget); expect(find.text('ROAD CAPTAIN'), findsOneWidget); expect(find.text('TAIL GUNNER'), findsOneWidget); expect(find.text('ROAD MARSHAL'), findsOneWidget); expect(find.text('FULL MEMBER'), findsOneWidget); }); }); }