Files
photo-live/apps/mobile/test/app/theme_test.dart
T

172 lines
6.0 KiB
Dart
Raw Normal View History

/// UI-01 主题一致性测试(Task 3)。
///
/// 覆盖:浅色 ColorScheme 方案 §3.1 精确值、深色语义对应值、字阶
/// (UI-03 §3 校准:24/17/16-14/13-12)、组件主题(按钮高 48/圆角 12、
/// 输入圆角 12、Dialog 圆角 16、BottomSheet 顶部圆角 16、AppBar
/// titleLarge)、动效令牌(含「减少动态效果」归零)。
library;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:photo_live/app/theme.dart';
import 'package:photo_live/ui/tokens.dart';
void main() {
group('浅色 ColorScheme(方案 §3.1 精确值)', () {
final scheme = AppTheme.light.colorScheme;
test('基础色', () {
expect(scheme.primary, const Color(0xFF1A73E8));
expect(scheme.onPrimary, const Color(0xFFFFFFFF));
expect(scheme.surface, const Color(0xFFFFFFFF));
expect(scheme.onSurface, const Color(0xFF172033));
expect(scheme.secondary, const Color(0xFF996300), reason: '等待色');
expect(scheme.error, const Color(0xFFB42318));
// 成功色不进 ColorScheme(独立令牌)。
expect(kColorSuccess, const Color(0xFF16794B));
});
test('页面背景与分隔线/次文字', () {
expect(AppTheme.light.scaffoldBackgroundColor, const Color(0xFFF6F8FB));
expect(AppTheme.light.dividerTheme.color, kColorDivider);
expect(kColorDivider, const Color(0xFFE5EAF1));
expect(scheme.onSurfaceVariant, kColorTextSecondary);
expect(kColorTextSecondary, const Color(0xFF69778E)); // UI06: app-preview --muted
});
});
group('深色 ColorScheme(语义对应,不反转图片)', () {
final theme = AppTheme.dark;
final scheme = theme.colorScheme;
test('深表面 + 浅文字 + 提亮主色', () {
expect(scheme.brightness, Brightness.dark);
expect(scheme.surface, const Color(0xFF1F2530));
expect(scheme.onSurface, const Color(0xFFE6EAF2));
expect(scheme.primary, kColorInfoDark);
expect(scheme.onPrimary, const Color(0xFF0B2E6F));
expect(theme.scaffoldBackgroundColor, const Color(0xFF12161D));
});
test('等待/错误为深色提亮变体', () {
expect(scheme.secondary, kColorWaitingDark);
expect(scheme.error, kColorErrorDark);
});
});
group('字阶(随系统缩放:fontSize 走 TextScaler)', () {
final textTheme = AppTheme.light.textTheme;
test('24 页面标题 / 17 分组 / 16-14 正文 / 13-12 辅助', () {
expect(textTheme.titleLarge!.fontSize, 24);
expect(textTheme.titleMedium!.fontSize, 17);
expect(textTheme.bodyLarge!.fontSize, 16);
expect(textTheme.bodyMedium!.fontSize, 14);
expect(textTheme.bodySmall!.fontSize, 13);
expect(textTheme.labelSmall!.fontSize, 12);
});
test('AppBar 标题用 titleLarge', () {
expect(AppTheme.light.appBarTheme.titleTextStyle!.fontSize, 24);
});
});
group('组件主题', () {
final theme = AppTheme.light;
test('按钮高 48、圆角 12', () {
final filled = theme.filledButtonTheme.style;
expect(
filled!.minimumSize!.resolve(const <WidgetState>{}),
const Size(64, 48),
);
expect(
theme.elevatedButtonTheme.style!.minimumSize!.resolve(
const <WidgetState>{},
),
const Size(64, 48),
);
final shape =
filled.shape!.resolve(const <WidgetState>{})
as RoundedRectangleBorder;
expect(shape.borderRadius, BorderRadius.circular(kRadiusInput));
expect(
theme.outlinedButtonTheme.style!.minimumSize!.resolve(
const <WidgetState>{},
),
const Size(48, 48),
);
expect(
theme.textButtonTheme.style!.minimumSize!.resolve(
const <WidgetState>{},
),
const Size(48, 48),
);
});
test('输入框圆角 10(UI06: app-preview .field)', () {
final border = theme.inputDecorationTheme.border as OutlineInputBorder;
expect(border.borderRadius, BorderRadius.circular(kRadiusField));
expect(kRadiusField, 10);
});
test('Dialog 圆角 16、BottomSheet 顶部圆角 16', () {
final dialog = theme.dialogTheme.shape as RoundedRectangleBorder;
expect(dialog.borderRadius, BorderRadius.circular(kRadiusCard));
final sheet = theme.bottomSheetTheme.shape as RoundedRectangleBorder;
expect(
(sheet.borderRadius as BorderRadius).topLeft,
const Radius.circular(kRadiusCard),
);
expect(
(sheet.borderRadius as BorderRadius).topRight,
const Radius.circular(kRadiusCard),
);
expect(kRadiusCard, 16);
});
test('底部导航无胶囊指示器(UI06: app-preview .nav)', () {
expect(theme.navigationBarTheme.indicatorColor, Colors.transparent);
});
});
group('动效令牌', () {
testWidgets('默认轻量 180ms / 轮播 300ms / 减少动态效果归零', (tester) async {
expect(kMotionFast, const Duration(milliseconds: 180));
expect(kMotionCarousel, const Duration(milliseconds: 300));
expect(kMotionReduce, Duration.zero);
late BuildContext captured;
await tester.pumpWidget(
MaterialApp(
home: Builder(
builder: (context) {
captured = context;
return const SizedBox.shrink();
},
),
),
);
expect(motion(captured), kMotionFast);
expect(motion(captured, carousel: true), kMotionCarousel);
// 「减少动态效果」开启 → 一律归零。
await tester.pumpWidget(
MaterialApp(
home: MediaQuery(
data: const MediaQueryData(disableAnimations: true),
child: Builder(
builder: (context) {
captured = context;
return const SizedBox.shrink();
},
),
),
),
);
expect(motion(captured), kMotionReduce);
expect(motion(captured, carousel: true), kMotionReduce);
});
});
}