132 lines
4.1 KiB
Dart
132 lines
4.1 KiB
Dart
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/widgets/slug_input_field.dart';
|
||
import 'package:motorcycle_dash/services/clubs/club_providers.dart';
|
||
import 'package:motorcycle_dash/services/clubs/club_service.dart';
|
||
import 'package:motorcycle_dash/services/clubs/club_slug_validator.dart';
|
||
|
||
class FakeClubService extends ClubService {
|
||
final Set<String> takenSlugs;
|
||
FakeClubService({this.takenSlugs = const {}});
|
||
|
||
@override
|
||
Future<bool> isSlugAvailable(String slug) async {
|
||
final validation = ClubSlugValidator.validate(slug);
|
||
if (!validation.isValid) return false;
|
||
return !takenSlugs.contains(validation.normalizedSlug!);
|
||
}
|
||
}
|
||
|
||
void main() {
|
||
group('SlugInputField Widget Tests', () {
|
||
late TextEditingController controller;
|
||
|
||
setUp(() {
|
||
controller = TextEditingController();
|
||
});
|
||
|
||
tearDown(() {
|
||
controller.dispose();
|
||
});
|
||
|
||
testWidgets('shows initial guidance and permanence warning', (tester) async {
|
||
await tester.pumpWidget(
|
||
ProviderScope(
|
||
overrides: [
|
||
clubServiceProvider.overrideWithValue(FakeClubService()),
|
||
],
|
||
child: MaterialApp(
|
||
theme: ThemeData.dark().copyWith(
|
||
extensions: [MotorSignalThemeColors.dark],
|
||
),
|
||
home: Scaffold(
|
||
body: SlugInputField(controller: controller),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
expect(find.text('Club Handle / Slug *'), findsOneWidget);
|
||
expect(
|
||
find.text('3–30 characters: lowercase letters, numbers, and single hyphens.'),
|
||
findsOneWidget,
|
||
);
|
||
expect(
|
||
find.text('Club handles are permanent and cannot be changed after creation. Choose carefully.'),
|
||
findsOneWidget,
|
||
);
|
||
});
|
||
|
||
testWidgets('shows validation error on invalid or reserved slugs', (tester) async {
|
||
await tester.pumpWidget(
|
||
ProviderScope(
|
||
overrides: [
|
||
clubServiceProvider.overrideWithValue(FakeClubService()),
|
||
],
|
||
child: MaterialApp(
|
||
theme: ThemeData.dark().copyWith(
|
||
extensions: [MotorSignalThemeColors.dark],
|
||
),
|
||
home: Scaffold(
|
||
body: SlugInputField(controller: controller),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
// Enter short slug
|
||
controller.text = 'ab';
|
||
await tester.pump();
|
||
expect(find.text('Club slug must be at least 3 characters'), findsOneWidget);
|
||
|
||
// Enter reserved slug
|
||
controller.text = 'admin';
|
||
await tester.pump();
|
||
expect(find.text('This club slug is reserved'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('debounces and reports availability', (tester) async {
|
||
bool? lastAvailability;
|
||
|
||
await tester.pumpWidget(
|
||
ProviderScope(
|
||
overrides: [
|
||
clubServiceProvider.overrideWithValue(
|
||
FakeClubService(takenSlugs: {'taken-slug'}),
|
||
),
|
||
],
|
||
child: MaterialApp(
|
||
theme: ThemeData.dark().copyWith(
|
||
extensions: [MotorSignalThemeColors.dark],
|
||
),
|
||
home: Scaffold(
|
||
body: SlugInputField(
|
||
controller: controller,
|
||
onValidationChanged: (val) => lastAvailability = val,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
// Enter valid available slug
|
||
controller.text = 'cool-riders';
|
||
await tester.pump(); // immediate update: checking
|
||
expect(find.text('Checking handle availability...'), findsOneWidget);
|
||
|
||
await tester.pump(const Duration(milliseconds: 500)); // after debounce
|
||
expect(find.text('Handle is available'), findsOneWidget);
|
||
expect(lastAvailability, isTrue);
|
||
|
||
// Enter taken slug
|
||
controller.text = 'taken-slug';
|
||
await tester.pump();
|
||
await tester.pump(const Duration(milliseconds: 500));
|
||
expect(find.text('Handle is already reserved by another club'), findsOneWidget);
|
||
expect(lastAvailability, isFalse);
|
||
});
|
||
});
|
||
}
|