import 'dart:async'; 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/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'; void main() { group('ClubDetailScreen Discovery UI State Tests', () { const testUser = AuthUser(uid: 'rider_alice', isAnonymous: false); final testClub = Club( id: 'club_alpha', name: 'Alpha Riders', slug: 'alpha-riders', description: 'The premier Alpha motorcycle community', ownerUid: 'owner_bob', memberCount: 15, visibility: ClubVisibility.public, admissionPolicy: ClubAdmissionPolicy.open, createdAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); final activeMember = ClubMember( clubId: 'club_alpha', uid: 'rider_alice', role: ClubRole.member, status: ClubMemberStatus.active, joinedAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); Widget buildTestWidget({ bool overrideMember = false, ClubMember? memberOverride, required AsyncValue> discoveryOverride, }) { return ProviderScope( overrides: [ currentUserProvider.overrideWithValue(testUser), clubDetailProvider('club_alpha').overrideWith((ref) => Stream.value(testClub)), currentMemberProvider('club_alpha').overrideWith( (ref) => Stream.value(overrideMember ? memberOverride : activeMember), ), clubDiscoveryRidesProvider('club_alpha').overrideWith((ref) => discoveryOverride.when( data: (data) => Future.value(data), error: (e, s) => Future.error(e, s), loading: () => Completer>().future, )), ], child: MaterialApp( theme: ThemeData.dark().copyWith( extensions: [MotorSignalThemeColors.dark], ), home: const ClubDetailScreen(clubId: 'club_alpha'), ), ); } testWidgets('Non-member sees active members only notice', (tester) async { await tester.binding.setSurfaceSize(const Size(800, 2400)); addTearDown(() => tester.binding.setSurfaceSize(null)); await tester.pumpWidget( buildTestWidget( overrideMember: true, memberOverride: null, discoveryOverride: const AsyncValue.data([]), ), ); await tester.pumpAndSettle(); expect(find.text('CLUB RIDES'), findsOneWidget); expect(find.text('Club rides are visible to active members only.'), findsOneWidget); }); testWidgets('Active member sees loading progress indicator during discovery fetch', (tester) async { await tester.binding.setSurfaceSize(const Size(800, 2400)); addTearDown(() => tester.binding.setSurfaceSize(null)); await tester.pumpWidget( buildTestWidget( discoveryOverride: const AsyncValue.loading(), ), ); await tester.pump(); expect(find.text('CLUB RIDES'), findsOneWidget); expect(find.byType(CircularProgressIndicator), findsOneWidget); }); testWidgets('Active member sees empty state when 0 upcoming rides found', (tester) async { await tester.binding.setSurfaceSize(const Size(800, 2400)); addTearDown(() => tester.binding.setSurfaceSize(null)); await tester.pumpWidget( buildTestWidget( discoveryOverride: const AsyncValue.data([]), ), ); await tester.pumpAndSettle(); expect(find.text('CLUB RIDES'), findsOneWidget); expect(find.text('No upcoming club rides scheduled.'), findsOneWidget); }); testWidgets('Active member sees populated discovery ride cards', (tester) async { await tester.binding.setSurfaceSize(const Size(800, 2400)); addTearDown(() => tester.binding.setSurfaceSize(null)); final testRides = [ ClubRideDiscovery( rideId: 'ride_101', clubId: 'club_alpha', title: 'Sunday Morning Twisties', scheduledStartAt: DateTime(2026, 9, 27, 9, 0), departureAt: DateTime(2026, 9, 27, 9, 30), joinPolicy: 'requestToJoin', participantCount: 6, participantLimit: 12, meetingLocationLabel: 'Lookout Point Parking', paceClassification: 'Moderate', organizerDisplayName: 'Captain Dan', ), ]; await tester.pumpWidget( buildTestWidget( discoveryOverride: AsyncValue.data(testRides), ), ); await tester.pumpAndSettle(); expect(find.text('CLUB RIDES'), findsOneWidget); expect(find.text('Sunday Morning Twisties'), findsOneWidget); expect(find.text('REQUEST TO JOIN'), findsOneWidget); expect(find.text('Lookout Point Parking'), findsOneWidget); expect(find.text('6 / 12 riders'), findsOneWidget); expect(find.text('Moderate'), findsOneWidget); expect(find.text('Captain Dan'), findsOneWidget); }); testWidgets('Active member sees error state with retry button on failure', (tester) async { await tester.binding.setSurfaceSize(const Size(800, 2400)); addTearDown(() => tester.binding.setSurfaceSize(null)); await tester.pumpWidget( buildTestWidget( discoveryOverride: const AsyncValue.error( ClubOperationException('Network error', code: 'network_error'), StackTrace.empty, ), ), ); await tester.pumpAndSettle(); expect(find.text('CLUB RIDES'), findsOneWidget); expect(find.text('Network connection issue. Please check your connection and try again.'), findsOneWidget); expect(find.widgetWithText(OutlinedButton, 'Retry'), findsOneWidget); }); }); }