603 lines
21 KiB
Dart
603 lines
21 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:http/http.dart' as http;
|
|
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';
|
|
|
|
class MockClubServiceForDetail extends ClubService {
|
|
String? lastAction;
|
|
String? lastClubId;
|
|
bool? lastAccept;
|
|
|
|
@override
|
|
Future<void> joinOpenClub(String clubId, {String? callerUid}) async {
|
|
lastAction = 'joinOpen';
|
|
lastClubId = clubId;
|
|
}
|
|
|
|
@override
|
|
Future<void> requestToJoinClub(String clubId, {String? callerUid}) async {
|
|
lastAction = 'requestToJoin';
|
|
lastClubId = clubId;
|
|
}
|
|
|
|
@override
|
|
Future<void> withdrawJoinRequest(String clubId, {String? callerUid}) async {
|
|
lastAction = 'withdrawRequest';
|
|
lastClubId = clubId;
|
|
}
|
|
|
|
@override
|
|
Future<void> respondToInvitation(String clubId, {required bool accept, String? callerUid}) async {
|
|
lastAction = 'respondInvite';
|
|
lastClubId = clubId;
|
|
lastAccept = accept;
|
|
}
|
|
|
|
@override
|
|
Future<void> leaveClub(String clubId, {String? callerUid}) async {
|
|
lastAction = 'leaveClub';
|
|
lastClubId = clubId;
|
|
}
|
|
|
|
@override
|
|
Future<List<ClubRideDiscovery>> fetchClubDiscoveryRides(
|
|
String clubId, {
|
|
http.Client? client,
|
|
String? baseUrl,
|
|
}) async {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
group('ClubDetailScreen Widget Lifecycle Tests', () {
|
|
late MockClubServiceForDetail mockService;
|
|
const testUser = AuthUser(uid: 'rider_1', isAnonymous: false);
|
|
|
|
final openClub = Club(
|
|
id: 'club_open',
|
|
name: 'Open Track Riders',
|
|
slug: 'open-track',
|
|
description: 'Track day motorcycle community',
|
|
ownerUid: 'owner_bob',
|
|
memberCount: 12,
|
|
visibility: ClubVisibility.public,
|
|
admissionPolicy: ClubAdmissionPolicy.open,
|
|
createdAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
final requestClub = Club(
|
|
id: 'club_request',
|
|
name: 'Sierra Twisties',
|
|
slug: 'sierra-twisties',
|
|
description: 'Mountain pass riding group',
|
|
ownerUid: 'owner_charlie',
|
|
memberCount: 5,
|
|
visibility: ClubVisibility.public,
|
|
admissionPolicy: ClubAdmissionPolicy.request,
|
|
createdAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
final inviteClub = Club(
|
|
id: 'club_invite',
|
|
name: 'Elite Racers',
|
|
slug: 'elite-racers',
|
|
description: 'Strictly invite only',
|
|
ownerUid: 'owner_dan',
|
|
memberCount: 3,
|
|
visibility: ClubVisibility.public,
|
|
admissionPolicy: ClubAdmissionPolicy.inviteOnly,
|
|
createdAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
setUp(() {
|
|
mockService = MockClubServiceForDetail();
|
|
});
|
|
|
|
testWidgets('renders Open Admission state and executes Join Club', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(null)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('OPEN ADMISSION'), findsOneWidget);
|
|
expect(find.text('Open Membership'), findsOneWidget);
|
|
final joinButton = find.widgetWithText(FilledButton, 'Join Club');
|
|
expect(joinButton, findsOneWidget);
|
|
|
|
await tester.tap(joinButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(mockService.lastAction, 'joinOpen');
|
|
expect(mockService.lastClubId, 'club_open');
|
|
});
|
|
|
|
testWidgets('renders Request Admission state and executes Request to Join', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_request').overrideWith((ref) => Stream.value(requestClub)),
|
|
currentMemberProvider('club_request').overrideWith((ref) => Stream.value(null)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_request'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('REQUEST REQUIRED'), findsOneWidget);
|
|
expect(find.text('Request Admission'), findsOneWidget);
|
|
final requestButton = find.widgetWithText(FilledButton, 'Request to Join');
|
|
expect(requestButton, findsOneWidget);
|
|
|
|
await tester.tap(requestButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(mockService.lastAction, 'requestToJoin');
|
|
expect(mockService.lastClubId, 'club_request');
|
|
});
|
|
|
|
testWidgets('renders Invite-Only state with no join action', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_invite').overrideWith((ref) => Stream.value(inviteClub)),
|
|
currentMemberProvider('club_invite').overrideWith((ref) => Stream.value(null)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_invite'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Invite-Only Club'), findsOneWidget);
|
|
expect(find.text('Join Club'), findsNothing);
|
|
expect(find.text('Request to Join'), findsNothing);
|
|
});
|
|
|
|
testWidgets('renders Invited state with Accept and Decline actions', (tester) async {
|
|
final inviteMember = ClubMember(
|
|
uid: 'rider_1',
|
|
clubId: 'club_request',
|
|
status: ClubMemberStatus.invited,
|
|
role: ClubRole.member,
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_request').overrideWith((ref) => Stream.value(requestClub)),
|
|
currentMemberProvider('club_request').overrideWith((ref) => Stream.value(inviteMember)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_request'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('INVITED'), findsOneWidget);
|
|
expect(find.text('You Are Invited'), findsOneWidget);
|
|
expect(find.text('Accept'), findsOneWidget);
|
|
expect(find.text('Decline'), findsOneWidget);
|
|
|
|
await tester.tap(find.text('Accept'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(mockService.lastAction, 'respondInvite');
|
|
expect(mockService.lastAccept, isTrue);
|
|
});
|
|
|
|
testWidgets('renders Requested state with Withdraw Request action', (tester) async {
|
|
final requestMember = ClubMember(
|
|
uid: 'rider_1',
|
|
clubId: 'club_request',
|
|
status: ClubMemberStatus.requested,
|
|
role: ClubRole.member,
|
|
requestedAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_request').overrideWith((ref) => Stream.value(requestClub)),
|
|
currentMemberProvider('club_request').overrideWith((ref) => Stream.value(requestMember)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_request'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('REQUEST PENDING'), findsOneWidget);
|
|
expect(find.text('Membership Requested'), findsOneWidget);
|
|
expect(find.text('Withdraw Request'), findsOneWidget);
|
|
|
|
await tester.tap(find.text('Withdraw Request'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(mockService.lastAction, 'withdrawRequest');
|
|
});
|
|
|
|
testWidgets('renders Active Member state with Leave Club and confirmation dialog', (tester) async {
|
|
final activeMember = ClubMember(
|
|
uid: 'rider_1',
|
|
clubId: 'club_open',
|
|
status: ClubMemberStatus.active,
|
|
role: ClubRole.member,
|
|
joinedAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(activeMember)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('MEMBER'), findsOneWidget);
|
|
expect(find.text('Active Member'), findsOneWidget);
|
|
expect(find.text('Leave Club'), findsOneWidget);
|
|
|
|
// Tap Leave Club to open confirmation dialog
|
|
await tester.tap(find.text('Leave Club'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Leave Open Track Riders?'), findsOneWidget);
|
|
expect(find.text('Cancel'), findsOneWidget);
|
|
|
|
// Confirm leaving inside the dialog
|
|
final confirmButtonFinder = find.widgetWithText(FilledButton, 'Leave Club');
|
|
expect(confirmButtonFinder, findsOneWidget);
|
|
await tester.tap(confirmButtonFinder);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(mockService.lastAction, 'leaveClub');
|
|
expect(mockService.lastClubId, 'club_open');
|
|
});
|
|
|
|
testWidgets('renders Owner state with ownership transfer constraint note and no leave button', (tester) async {
|
|
const ownerUser = AuthUser(uid: 'owner_bob', isAnonymous: false);
|
|
final ownerMember = ClubMember(
|
|
uid: 'owner_bob',
|
|
clubId: 'club_open',
|
|
status: ClubMemberStatus.active,
|
|
role: ClubRole.owner,
|
|
joinedAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => ownerUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(ownerMember)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Club Owner'), findsOneWidget);
|
|
expect(find.textContaining('Ownership must be transferred before leaving'), findsOneWidget);
|
|
expect(find.text('Leave Club'), findsNothing);
|
|
});
|
|
|
|
testWidgets('renders loading state and prevents action button clicks while membership is loading', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => const Stream.empty()),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pump();
|
|
|
|
expect(find.text('Checking Membership Status...'), findsOneWidget);
|
|
expect(find.text('Join Club'), findsNothing);
|
|
expect(find.text('Request to Join'), findsNothing);
|
|
expect(find.text('Leave Club'), findsNothing);
|
|
});
|
|
|
|
testWidgets('renders retryable error state when membership stream errors', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.error(Exception('Network error'))),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Membership Status Unavailable'), findsOneWidget);
|
|
expect(find.text('Retry'), findsOneWidget);
|
|
expect(find.text('Join Club'), findsNothing);
|
|
expect(find.text('Leave Club'), findsNothing);
|
|
});
|
|
|
|
testWidgets('renders clean unavailable screen with back navigation on club stream error', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('private_club').overrideWith((ref) => Stream.error(Exception('permission-denied'))),
|
|
currentMemberProvider('private_club').overrideWith((ref) => const Stream.empty()),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'private_club'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Club Unavailable'), findsOneWidget);
|
|
expect(find.text('Unable to display this club at this time.'), findsOneWidget);
|
|
expect(find.text('Back to Clubs'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('renders without overflow on portrait 412x915', (tester) async {
|
|
tester.view.physicalSize = const Size(412, 915);
|
|
tester.view.devicePixelRatio = 1.0;
|
|
addTearDown(() => tester.view.resetPhysicalSize());
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(null)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(tester.takeException(), isNull);
|
|
|
|
// Scroll to bottom
|
|
await tester.drag(find.byType(SingleChildScrollView), const Offset(0, -400));
|
|
await tester.pumpAndSettle();
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('renders without overflow on landscape 915x412 including dialog', (tester) async {
|
|
tester.view.physicalSize = const Size(915, 412);
|
|
tester.view.devicePixelRatio = 1.0;
|
|
addTearDown(() => tester.view.resetPhysicalSize());
|
|
|
|
final activeMember = ClubMember(
|
|
uid: 'rider_1',
|
|
clubId: 'club_open',
|
|
status: ClubMemberStatus.active,
|
|
role: ClubRole.member,
|
|
joinedAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(activeMember)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(tester.takeException(), isNull);
|
|
|
|
// Open leave confirmation dialog
|
|
await tester.ensureVisible(find.text('Leave Club'));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('Leave Club'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Leave Open Track Riders?'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('non-member sees member-only informational card for club rides', (tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(null)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('CLUB RIDES'), findsOneWidget);
|
|
expect(find.text('Club rides are visible to active members only.'), findsOneWidget);
|
|
expect(find.text('Plan Club Ride'), findsNothing);
|
|
});
|
|
|
|
testWidgets('active member sees discovery list and admin sees Plan Club Ride button', (tester) async {
|
|
final activeAdmin = ClubMember(
|
|
uid: 'rider_1',
|
|
clubId: 'club_open',
|
|
status: ClubMemberStatus.active,
|
|
role: ClubRole.admin,
|
|
joinedAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(activeAdmin)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('CLUB RIDES'), findsOneWidget);
|
|
expect(find.text('No upcoming club rides scheduled.'), findsOneWidget);
|
|
expect(find.text('Plan Club Ride'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('active ordinary member sees discovery list and no Plan button', (tester) async {
|
|
final activeMember = ClubMember(
|
|
uid: 'rider_2',
|
|
clubId: 'club_open',
|
|
status: ClubMemberStatus.active,
|
|
role: ClubRole.member,
|
|
joinedAt: DateTime(2026, 1, 1),
|
|
updatedAt: DateTime(2026, 1, 1),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => testUser),
|
|
clubServiceProvider.overrideWithValue(mockService),
|
|
clubDetailProvider('club_open').overrideWith((ref) => Stream.value(openClub)),
|
|
currentMemberProvider('club_open').overrideWith((ref) => Stream.value(activeMember)),
|
|
],
|
|
child: MaterialApp(
|
|
theme: ThemeData.dark().copyWith(
|
|
extensions: [MotorSignalThemeColors.dark],
|
|
),
|
|
home: const ClubDetailScreen(clubId: 'club_open'),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('CLUB RIDES'), findsOneWidget);
|
|
expect(find.text('No upcoming club rides scheduled.'), findsOneWidget);
|
|
expect(find.text('Plan Club Ride'), findsNothing);
|
|
});
|
|
});
|
|
}
|