Drama 新增 tagCode,推荐页只看 NEW_ARRIVAL 这个码决定上新横滑, 不再依赖可变的标签文案;分类网格高度改为复用卡片的统一常量。 头部轮播改用虚拟无限页码,首尾相接且能反向滑,自动播放不再倒滑回第一张。
This commit is contained in:
1 parent
c311985601
commit
3590cd0c55
5 files changed
+235
-73
No files matched your search
@@ -0,0 +1,83 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/core/data/models/home_feed.dart';
|
||||
import 'package:fruitshorts/core/theme/app_colors.dart';
|
||||
import 'package:fruitshorts/l10n/app_localizations.dart';
|
||||
import 'package:fruitshorts/pages/recommend/widgets/home_hero_carousel.dart';
|
||||
|
||||
const List<FeedBanner> _banners = [
|
||||
FeedBanner(id: '1', imageUrl: 'https://cdn.test/a.png'),
|
||||
FeedBanner(id: '2', imageUrl: 'https://cdn.test/b.png'),
|
||||
];
|
||||
|
||||
Widget _harness(List<FeedBanner> banners) {
|
||||
return MaterialApp(
|
||||
locale: const Locale('en'),
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: HomeHeroCarousel(
|
||||
banners: banners,
|
||||
dramaFor: (_) => null,
|
||||
onWatch: (_) {},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color? _dotColor(WidgetTester tester, int index) {
|
||||
final decoration =
|
||||
tester
|
||||
.widget<Container>(find.byKey(Key('home-hero-dot-$index')))
|
||||
.decoration
|
||||
as BoxDecoration?;
|
||||
return decoration?.color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('should_keep_looping_backwards_from_the_first_banner', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(_harness(_banners));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(_dotColor(tester, 0), AppColors.brandRed);
|
||||
|
||||
// 从第一张往右滑:无缝轮播应该接到最后一张,而不是被边界挡住。
|
||||
await tester.fling(find.byType(PageView), const Offset(700, 0), 1200);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(_dotColor(tester, 1), AppColors.brandRed);
|
||||
expect(_dotColor(tester, 0), isNot(AppColors.brandRed));
|
||||
});
|
||||
|
||||
testWidgets('should_wrap_to_first_banner_after_last_auto_advance', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(_harness(_banners));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 自动播两次:第 2 张之后应回到第 1 张,且页码继续往前走不回头。
|
||||
await tester.pump(const Duration(milliseconds: 4600));
|
||||
await tester.pumpAndSettle();
|
||||
expect(_dotColor(tester, 1), AppColors.brandRed);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 4600));
|
||||
await tester.pumpAndSettle();
|
||||
expect(_dotColor(tester, 0), AppColors.brandRed);
|
||||
});
|
||||
|
||||
testWidgets('should_not_loop_when_only_one_banner', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
_harness(const [FeedBanner(id: '1', imageUrl: 'https://cdn.test/a.png')]),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('home-hero-dot-0')), findsNothing);
|
||||
await tester.pump(const Duration(milliseconds: 6000));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/app.dart';
|
||||
import 'package:fruitshorts/core/data/models/drama.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart';
|
||||
@@ -10,6 +11,7 @@ import 'package:fruitshorts/core/theme/app_colors.dart';
|
||||
import 'package:fruitshorts/core/theme/app_dimens.dart';
|
||||
import 'package:fruitshorts/core/widgets/app_bottom_nav.dart';
|
||||
import 'package:fruitshorts/pages/player/player_view.dart';
|
||||
import 'package:fruitshorts/pages/recommend/recommend_discover_page.dart';
|
||||
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
|
||||
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
|
||||
|
||||
@@ -34,7 +36,10 @@ void main() {
|
||||
expect(find.byKey(const Key('recommend-tab-recommend')), findsOneWidget);
|
||||
expect(find.byKey(const Key('recommend-tab-playlist')), findsOneWidget);
|
||||
expect(find.byKey(const Key('recommend-tab-all')), findsOneWidget);
|
||||
expect(find.byKey(const Key('recommend-feed-player'), skipOffstage: false), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('recommend-feed-player'), skipOffstage: false),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('recommend-top-gradient')), findsOneWidget);
|
||||
final recommendText = tester.widget<Text>(
|
||||
find.descendant(
|
||||
@@ -65,7 +70,9 @@ void main() {
|
||||
find.byKey(const Key('recommend-top-nav')),
|
||||
);
|
||||
// 右侧依次是搜索和金色礼物盒(钱包入口),礼物盒贴右边距 8。
|
||||
final searchRect = tester.getRect(find.byKey(const Key('recommend-search')));
|
||||
final searchRect = tester.getRect(
|
||||
find.byKey(const Key('recommend-search')),
|
||||
);
|
||||
final giftRect = tester.getRect(find.byKey(const Key('recommend-gift')));
|
||||
expect(giftRect.right, closeTo(topNavRect.right - 8, 0.1));
|
||||
expect(searchRect.right, lessThanOrEqualTo(giftRect.left));
|
||||
@@ -78,7 +85,12 @@ void main() {
|
||||
tester
|
||||
.getRect(find.byKey(const Key('recommend-top-nav')))
|
||||
.overlaps(
|
||||
tester.getRect(find.byKey(const Key('recommend-feed-player'), skipOffstage: false)),
|
||||
tester.getRect(
|
||||
find.byKey(
|
||||
const Key('recommend-feed-player'),
|
||||
skipOffstage: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
@@ -387,7 +399,10 @@ void main() {
|
||||
tester.getRect(find.byKey(const Key('all-dramas-filters'))).top,
|
||||
closeTo(fixedFilterTop, 0.1),
|
||||
);
|
||||
expect(find.byKey(const Key('all-filter-classification-all')), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('all-filter-classification-all')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('all-filter-category-all')), findsOneWidget);
|
||||
expect(find.byKey(const Key('all-filter-tag-all')), findsOneWidget);
|
||||
expect(
|
||||
@@ -407,7 +422,10 @@ void main() {
|
||||
await tester.tap(find.byKey(const Key('recommend-tab-playlist')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('recommend-section-hits')), findsOneWidget);
|
||||
expect(find.byKey(const Key('recommend-feed-player'), skipOffstage: false), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('recommend-feed-player'), skipOffstage: false),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byType(AppBottomNav), findsOneWidget);
|
||||
|
||||
await tester.ensureVisible(find.byKey(const Key('recommend-tab-all')));
|
||||
@@ -430,7 +448,10 @@ void main() {
|
||||
await tester.drag(pages, const Offset(-320, 0));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('recommend-section-hits')), findsOneWidget);
|
||||
expect(find.byKey(const Key('recommend-feed-player'), skipOffstage: false), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('recommend-feed-player'), skipOffstage: false),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(
|
||||
tester
|
||||
.widget<Text>(
|
||||
@@ -454,7 +475,10 @@ void main() {
|
||||
|
||||
await tester.drag(pages, const Offset(640, 0));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('recommend-feed-player'), skipOffstage: false), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('recommend-feed-player'), skipOffstage: false),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('recommend-tab-recommend')), findsOneWidget);
|
||||
_drainOverflows(tester);
|
||||
});
|
||||
@@ -497,7 +521,9 @@ void main() {
|
||||
await _pumpRecommend(tester);
|
||||
|
||||
final gesture = await tester.startGesture(
|
||||
tester.getCenter(find.byKey(const Key('recommend-feed-player'), skipOffstage: false)),
|
||||
tester.getCenter(
|
||||
find.byKey(const Key('recommend-feed-player'), skipOffstage: false),
|
||||
),
|
||||
);
|
||||
await gesture.moveBy(const Offset(0, 80));
|
||||
await tester.pump();
|
||||
@@ -505,7 +531,10 @@ void main() {
|
||||
final feedScroll = tester.state<ScrollableState>(
|
||||
find
|
||||
.descendant(
|
||||
of: find.byKey(const Key('recommend-feed-player'), skipOffstage: false),
|
||||
of: find.byKey(
|
||||
const Key('recommend-feed-player'),
|
||||
skipOffstage: false,
|
||||
),
|
||||
matching: find.byType(Scrollable),
|
||||
)
|
||||
.first,
|
||||
@@ -544,6 +573,25 @@ void main() {
|
||||
expect(search.focusNode?.hasFocus, isTrue);
|
||||
_drainOverflows(tester);
|
||||
});
|
||||
|
||||
test('should_judge_new_arrival_only_by_tag_code', () {
|
||||
Drama tagged({String tagCode = '', String tag = ''}) => Drama(
|
||||
id: 'tagged',
|
||||
title: 'Tagged',
|
||||
synopsis: 'synopsis',
|
||||
posterUrl: '',
|
||||
tag: tag,
|
||||
tagCode: tagCode,
|
||||
);
|
||||
|
||||
expect(isNewArrivalTag(tagged(tagCode: 'NEW_ARRIVAL')), isTrue);
|
||||
expect(isNewArrivalTag(tagged(tagCode: ' new_arrival ')), isTrue);
|
||||
// 其它语义码(以及没有码的标签)都不算上新,文案不参与判断。
|
||||
expect(isNewArrivalTag(tagged(tagCode: 'HOT')), isFalse);
|
||||
expect(isNewArrivalTag(tagged(tagCode: 'NEW_RELEASE')), isFalse);
|
||||
expect(isNewArrivalTag(tagged(tag: '上新')), isFalse);
|
||||
expect(isNewArrivalTag(tagged()), isFalse);
|
||||
});
|
||||
}
|
||||
|
||||
/// 测试字体(等宽方块字形)比真实字体宽/高,卡片固定高度会报 2~4px
|
||||
|
||||
Reference in new issue
Block a user