MotorSignal-App/test/theme_test.dart

135 lines
5.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:motorcycle_dash/core/theme/app_colors.dart';
import 'package:motorcycle_dash/core/theme/app_spacing.dart';
import 'package:motorcycle_dash/core/theme/app_typography.dart';
import 'package:motorcycle_dash/core/theme/theme.dart';
import 'package:motorcycle_dash/core/theme/theme_extensions.dart';
import 'package:motorcycle_dash/core/theme/theme_mode_provider.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('MotorSignal Design System - Tokens & Hierarchy', () {
test('AppColors verifies dark and light semantic palette definitions', () {
expect(AppColors.cyberCyan, const Color(0xFF00B4D8));
expect(AppColors.velocityBlue, const Color(0xFF0096C7));
expect(AppColors.raceRed, const Color(0xFFFF3B30));
expect(AppColors.darkBackground, const Color(0xFF0D0F13));
expect(AppColors.darkSurface, const Color(0xFF13171E));
expect(AppColors.lightBackground, const Color(0xFFF3F5F8));
expect(AppColors.lightSurface, const Color(0xFFE9EDF2));
});
test('AppTypography specifies authoritative multi-font system', () {
expect(AppTypography.fontTelemetry, 'JetBrains Mono');
expect(AppTypography.fontHeadline, 'Sora');
expect(AppTypography.fontBody, 'Inter');
expect(AppTypography.speedometer.fontFamily, 'JetBrains Mono');
expect(AppTypography.speedometer.fontSize, 96);
expect(AppTypography.speedometer.fontWeight, FontWeight.w900);
expect(AppTypography.headingCompass.fontFamily, 'Sora');
expect(AppTypography.bodyMd.fontFamily, 'Inter');
expect(AppTypography.button.fontFamily, 'Sora');
});
test('AppSpacing and AppRadius conform to 4dp base grid and 48dp touch targets', () {
expect(AppSpacing.xs, 4.0);
expect(AppSpacing.sm, 8.0);
expect(AppSpacing.md, 12.0);
expect(AppSpacing.lg, 16.0);
expect(AppSpacing.xl, 24.0);
expect(AppSpacing.minTouchTarget, 48.0);
expect(AppRadius.sm, 4.0);
expect(AppRadius.md, 8.0);
expect(AppRadius.lg, 12.0);
expect(AppRadius.xl, 16.0);
expect(AppRadius.full, 999.0);
});
});
group('MotorSignalThemeColors Extension', () {
test('Dark and Light presets have correct brightness semantics', () {
const dark = MotorSignalThemeColors.dark;
expect(dark.cyberCyan, AppColors.cyberCyan);
expect(dark.launchGreen, AppColors.launchGreen);
expect(dark.surfaceContainer, AppColors.darkSurfaceContainer);
const light = MotorSignalThemeColors.light;
expect(light.cyberCyan, AppColors.technicalBlue);
expect(light.launchGreen, AppColors.launchGreen);
expect(light.surfaceContainer, AppColors.lightSurfaceContainer);
});
test('copyWith and lerp interpolate colors accurately', () {
const dark = MotorSignalThemeColors.dark;
final modified = dark.copyWith(cyberCyan: Colors.purple);
expect(modified.cyberCyan, Colors.purple);
expect(modified.velocityBlue, dark.velocityBlue);
final lerped = dark.lerp(MotorSignalThemeColors.light, 0.5);
expect(lerped, isA<MotorSignalThemeColors>());
expect(lerped.cyberCyan, Color.lerp(dark.cyberCyan, MotorSignalThemeColors.light.cyberCyan, 0.5));
});
});
group('AppTheme ThemeData', () {
test('darkTheme configures Material 3 dark brightness and extensions', () {
final theme = AppTheme.darkTheme;
expect(theme.useMaterial3, isTrue);
expect(theme.brightness, Brightness.dark);
expect(theme.scaffoldBackgroundColor, AppColors.darkBackground);
expect(theme.colorScheme.primary, AppColors.darkPrimary);
final ext = theme.extension<MotorSignalThemeColors>();
expect(ext, isNotNull);
expect(ext?.cyberCyan, AppColors.cyberCyan);
});
test('lightTheme configures Material 3 light brightness and extensions', () {
final theme = AppTheme.lightTheme;
expect(theme.useMaterial3, isTrue);
expect(theme.brightness, Brightness.light);
expect(theme.scaffoldBackgroundColor, AppColors.lightBackground);
expect(theme.colorScheme.primary, AppColors.lightPrimary);
final ext = theme.extension<MotorSignalThemeColors>();
expect(ext, isNotNull);
expect(ext?.cyberCyan, AppColors.technicalBlue);
});
});
group('ThemeMode & Persistence Provider', () {
test('AppThemeModeNotifier defaults to ThemeMode.system and persists transitions', () async {
SharedPreferences.setMockInitialValues({});
final prefs = await SharedPreferences.getInstance();
final notifier = AppThemeModeNotifier(prefs);
expect(notifier.state, ThemeMode.system);
await notifier.setThemeMode(ThemeMode.dark);
expect(notifier.state, ThemeMode.dark);
expect(prefs.getString('app_theme_mode'), 'dark');
await notifier.setThemeMode(ThemeMode.light);
expect(notifier.state, ThemeMode.light);
expect(prefs.getString('app_theme_mode'), 'light');
await notifier.toggleTheme();
expect(notifier.state, ThemeMode.system);
});
test('AppThemeModeNotifier restores saved theme from SharedPreferences', () async {
SharedPreferences.setMockInitialValues({'app_theme_mode': 'light'});
final prefs = await SharedPreferences.getInstance();
final notifier = AppThemeModeNotifier(prefs);
expect(notifier.state, ThemeMode.light);
});
});
}