MotorSignal-App/test/slug_input_field_test.dart

132 lines
4.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
});
});
}