Files
ReelShort/test/player/player_more_sheet_test.dart
Zhou Weidong 1d4ab5e0e6 test: 按新 UI 基线重写过期用例
覆盖 155 条失败与 4 处编译错误:入口改走推荐流 tab、弹框换 AppGlowDialog、
rail 尺寸与底部锚定、子页标题字重 w400、底栏选中品牌红、收藏文案改收藏短剧。
全量 flutter test 775 通过。
2026-10-28 18:48:03 +08:00

273 lines
8.9 KiB
Dart

// Author: fruit.com.cn
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/theme/app_colors.dart';
import 'package:fruitshorts/core/widgets/app_glow_panel.dart';
import 'package:fruitshorts/l10n/app_localizations.dart';
import 'package:fruitshorts/pages/player/widgets/player_more_sheet.dart';
void main() {
testWidgets('should_hide_pip_row_when_platform_unsupported', (tester) async {
await _openSheet(tester);
expect(find.byKey(const Key('player-more-sheet')), findsOneWidget);
expect(find.byKey(const Key('player-more-clear')), findsOneWidget);
expect(find.byKey(const Key('player-more-offline')), findsOneWidget);
expect(find.byKey(const Key('player-more-pip')), findsNothing);
expect(find.byKey(const Key('player-more-close')), findsNothing);
});
testWidgets('should_render_reference_layout_metrics', (tester) async {
await _openSheet(tester);
// 弹框统一换成 AppGlowPanel 渐变外壳:外壳是主题红晕渐变,内层 Material 透明。
final shell = tester.widget<DecoratedBox>(
find
.descendant(
of: find.byType(AppGlowPanel),
matching: find.byType(DecoratedBox),
)
.first,
);
final shellDecoration = shell.decoration as BoxDecoration;
expect((shellDecoration.gradient! as LinearGradient).colors, [
AppColors.followingGlow,
AppColors.followingGlowMid,
const Color(0xFF101012),
]);
expect(
tester.widget<Material>(find.byKey(const Key('player-more-sheet'))).color,
isNull,
);
expect(
tester.getSize(find.byKey(const Key('player-more-drag-handle'))),
const Size(36, 4),
);
for (final key in const [
Key('player-more-speed-row'),
Key('player-more-quality-row'),
Key('player-more-clear'),
Key('player-more-offline'),
]) {
expect(tester.getSize(find.byKey(key)).height, 56);
}
for (final key in const [
Key('player-more-speed-track'),
Key('player-more-quality-track'),
]) {
expect(tester.getSize(find.byKey(key)).height, 34);
final trackDecoration =
tester.widget<Container>(find.byKey(key)).decoration!
as BoxDecoration;
// 渐变外壳上的分段轨道改成 8% 白色叠层,不再用实色 raised。
expect(trackDecoration.color, Colors.white.withValues(alpha: 0.08));
}
for (final key in const [
Key('player-more-speed-0.75'),
Key('player-more-speed-1.0'),
Key('player-more-speed-1.25'),
]) {
expect(tester.getSize(find.byKey(key)).height, 26);
}
final speedLabel = tester.widget<Text>(
find
.descendant(
of: find.byKey(const Key('player-more-speed-row')),
matching: find.byType(Text),
)
.first,
);
expect(speedLabel.style?.fontSize, 15);
expect(speedLabel.style?.fontWeight, FontWeight.w500);
expect(tester.widget<Icon>(find.byIcon(Icons.speed_outlined)).size, 22);
expect(tester.widget<Icon>(find.byIcon(Icons.fullscreen)).size, 22);
final selected = tester.widget<Container>(
find
.descendant(
of: find.byKey(const Key('player-more-speed-1.0')),
matching: find.byType(Container),
)
.first,
);
final selectedDecoration = selected.decoration! as BoxDecoration;
// 选中态同样改成 16% 白色叠层。
expect(selectedDecoration.color, Colors.white.withValues(alpha: 0.16));
expect(selectedDecoration.boxShadow, isNotEmpty);
final selectedText = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-more-speed-1.0')),
matching: find.text('1.0x'),
),
);
expect(selectedText.style?.color, AppColors.onSurface);
expect(selectedText.style?.fontSize, 13);
expect(selectedText.style?.fontWeight, FontWeight.w600);
final unselected = tester.widget<Container>(
find
.descendant(
of: find.byKey(const Key('player-more-speed-1.25')),
matching: find.byType(Container),
)
.first,
);
final unselectedDecoration = unselected.decoration! as BoxDecoration;
expect(unselectedDecoration.color, Colors.transparent);
final unselectedText = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-more-speed-1.25')),
matching: find.text('1.25x'),
),
);
expect(unselectedText.style?.color, AppColors.muted);
expect(unselectedText.style?.fontSize, 13);
expect(unselectedText.style?.fontWeight, FontWeight.w400);
final disabledText = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-more-quality-720P')),
matching: find.byType(Text),
),
);
expect(disabledText.style?.color, AppColors.subtle);
});
testWidgets('should_enable_quality_when_ticket_uses_lowercase_codes', (
tester,
) async {
await _openSheet(
tester,
qualities: const ['AUTO', '360p', '480p', '720p', '1080p'],
);
expect(find.text('720P'), findsOneWidget);
expect(find.text('1080P'), findsOneWidget);
expect(find.textContaining('暂不可用'), findsNothing);
final enabled = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-more-quality-720P')),
matching: find.byType(Text),
),
);
expect(enabled.style?.color, isNot(AppColors.subtle));
});
testWidgets('should_report_selected_quality_when_a_rendition_is_tapped', (
tester,
) async {
String? picked;
await _openSheet(
tester,
qualities: const ['AUTO', '720p'],
onQuality: (quality) async {
picked = quality;
return true;
},
);
await tester.ensureVisible(find.byKey(const Key('player-more-quality-720P')));
await tester.tap(find.byKey(const Key('player-more-quality-720P')));
await tester.pump();
expect(picked, '720P');
final selected = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-more-quality-720P')),
matching: find.byType(Text),
),
);
expect(selected.style?.color, AppColors.onSurface);
});
testWidgets('should_restore_previous_quality_when_switch_fails', (
tester,
) async {
await _openSheet(
tester,
qualities: const ['AUTO', '720p'],
onQuality: (_) async => false,
);
await tester.ensureVisible(find.byKey(const Key('player-more-quality-720P')));
await tester.tap(find.byKey(const Key('player-more-quality-720P')));
await tester.pumpAndSettle();
final restored = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-more-quality-AUTO')),
matching: find.byType(Text),
),
);
expect(restored.style?.color, AppColors.onSurface);
});
testWidgets('should_trigger_pip_and_close_sheet_when_tapped', (tester) async {
var pipCalls = 0;
await _openSheet(tester, onPip: () => pipCalls++);
expect(find.byKey(const Key('player-more-pip')), findsOneWidget);
expect(
tester.getTopLeft(find.byKey(const Key('player-more-clear'))).dy <
tester.getTopLeft(find.byKey(const Key('player-more-pip'))).dy,
isTrue,
);
expect(
tester.getTopLeft(find.byKey(const Key('player-more-pip'))).dy <
tester.getTopLeft(find.byKey(const Key('player-more-offline'))).dy,
isTrue,
);
await tester.tap(find.byKey(const Key('player-more-pip')));
await tester.pumpAndSettle();
expect(pipCalls, 1);
expect(find.byKey(const Key('player-more-sheet')), findsNothing);
});
}
Future<void> _openSheet(
WidgetTester tester, {
VoidCallback? onPip,
Future<bool> Function(String quality)? onQuality,
List<String> qualities = const ['AUTO'],
}) async {
await tester.pumpWidget(
MaterialApp(
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
home: Scaffold(
body: Builder(
builder: (context) => Center(
child: TextButton(
key: const Key('open-more-sheet'),
onPressed: () => showModalBottomSheet<void>(
context: context,
backgroundColor: Colors.transparent,
isScrollControlled: true,
builder: (_) => PlayerMoreSheet(
l10n: AppLocalizations.of(context)!,
state: PlayerMoreState(speed: 1.0, qualities: qualities),
actions: PlayerMoreActions(
onSpeedChanged: (_) {},
onClear: () {},
onDownload: () {},
onQualityChanged: onQuality ?? (_) async => true,
onPip: onPip,
),
),
),
child: const Text('open'),
),
),
),
),
),
);
await tester.tap(find.byKey(const Key('open-more-sheet')));
await tester.pumpAndSettle();
}