Files
photo-live/apps/mobile/test/app/theme_test.dart
T
2026-09-21 14:55:29 +08:00

175 lines
5.9 KiB
Dart
Raw 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.
/// UI-01 主题一致性测试(Task 3)。
///
/// 覆盖:浅色 ColorScheme 方案 §3.1 精确值、深色语义对应值、字阶
/// (22/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(0xFF5E6878));
});
});
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('22 页面标题 / 17 分组 / 16-14 正文 / 13-12 辅助', () {
expect(textTheme.titleLarge!.fontSize, 22);
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, 22);
});
});
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('输入框圆角 12', () {
final border = theme.inputDecorationTheme.border as OutlineInputBorder;
expect(border.borderRadius, BorderRadius.circular(kRadiusInput));
expect(kRadiusInput, 12);
});
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('底部导航指示器色已配置', () {
expect(
theme.navigationBarTheme.indicatorColor,
theme.colorScheme.secondaryContainer,
);
});
});
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);
});
});
}