848 lines
27 KiB
Dart
848 lines
27 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'dart:async';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.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';
|
|
|
|
import 'package:fruitshorts/app.dart';
|
|
import 'package:fruitshorts/core/data/models/content_category.dart';
|
|
import 'package:fruitshorts/core/data/models/drama.dart';
|
|
import 'package:fruitshorts/core/data/models/home_feed.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';
|
|
import 'package:fruitshorts/core/data/services/playback_thumbnail_service.dart';
|
|
import 'package:fruitshorts/core/theme/app_theme.dart';
|
|
import 'package:fruitshorts/l10n/app_localizations.dart';
|
|
import 'package:fruitshorts/pages/home/home_feed_channel.dart';
|
|
import 'package:fruitshorts/pages/player/widgets/home_feed_header.dart';
|
|
import 'package:fruitshorts/pages/player/widgets/home_feed_overlay.dart';
|
|
import 'package:fruitshorts/pages/player/player_view.dart';
|
|
import 'package:video_player/video_player.dart';
|
|
|
|
import '../support/fake_catalog.dart';
|
|
import '../support/fake_category.dart';
|
|
import '../support/fake_haptics.dart';
|
|
import '../support/fake_interaction_repositories.dart';
|
|
import '../support/fake_notice_repository.dart';
|
|
import '../support/widget_player.dart';
|
|
|
|
void main() {
|
|
testWidgets('should_render_three_column_explorer_grid_on_home', (
|
|
tester,
|
|
) async {
|
|
SharedPreferencesAsyncPlatform.instance =
|
|
InMemorySharedPreferencesAsync.empty();
|
|
tester.view.physicalSize = const Size(390, 844);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
final catalog = FakeCatalogRepository(
|
|
banners: const [
|
|
FeedBanner(
|
|
id: 'banner-1',
|
|
imageUrl: '/files/banner.jpg',
|
|
linkType: 'DRAMA',
|
|
linkValue: 'the-signal-demo',
|
|
),
|
|
],
|
|
);
|
|
await tester.pumpWidget(
|
|
LumaDramaApp(
|
|
playerFactory: createWidgetPlayer,
|
|
catalogRepository: catalog,
|
|
categoryRepository: FakeCategoryRepository(
|
|
catalog: catalog,
|
|
categories: const [
|
|
ContentCategory(id: 'costume', name: '古装'),
|
|
ContentCategory(id: 'community', name: '社群'),
|
|
],
|
|
),
|
|
watchHistoryRepository: InMemoryWatchHistoryRepository(),
|
|
favoriteRepository: InMemoryFavoriteRepository(cards: catalog.dramas),
|
|
playbackRepository: FakePlaybackRepository(),
|
|
commentRepository: FakeCommentRepository(),
|
|
interactionRepository: FakeInteractionRepository(),
|
|
noticeRepository: FakeNoticeRepository(),
|
|
haptics: FakeHaptics(),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('home-grid')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-grid-cards')), findsOneWidget);
|
|
final grid = tester.widget<SliverGrid>(
|
|
find.byKey(const Key('home-grid-cards')),
|
|
);
|
|
final delegate =
|
|
grid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
|
|
expect(delegate.crossAxisCount, 3);
|
|
expect(delegate.crossAxisSpacing, 8);
|
|
expect(delegate.mainAxisSpacing, 8);
|
|
expect(find.byKey(const Key('home-section-featured')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-section-new')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-section-categories')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-section-ranking')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-section-category-古装')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-section-category-社群')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-secondary-tags')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-grid-filter')), findsOneWidget);
|
|
expect(find.byType(PageView), findsNothing);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('should_show_section_feed_and_open_player_from_recommend', (
|
|
tester,
|
|
) async {
|
|
SharedPreferencesAsyncPlatform.instance =
|
|
InMemorySharedPreferencesAsync.empty();
|
|
tester.view.physicalSize = const Size(390, 844);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
final catalog = FakeCatalogRepository();
|
|
await tester.pumpWidget(
|
|
LumaDramaApp(
|
|
playerFactory: createWidgetPlayer,
|
|
catalogRepository: catalog,
|
|
categoryRepository: FakeCategoryRepository(catalog: catalog),
|
|
watchHistoryRepository: InMemoryWatchHistoryRepository(),
|
|
favoriteRepository: InMemoryFavoriteRepository(cards: catalog.dramas),
|
|
playbackRepository: FakePlaybackRepository(),
|
|
commentRepository: FakeCommentRepository(),
|
|
interactionRepository: FakeInteractionRepository(),
|
|
noticeRepository: FakeNoticeRepository(),
|
|
haptics: FakeHaptics(),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.byKey(const Key('tab-recommend')));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('home-grid')), findsNothing);
|
|
expect(find.byKey(const Key('recommend-page')), findsOneWidget);
|
|
expect(find.byKey(const Key('recommend-section-hits')), findsOneWidget);
|
|
expect(find.byType(PlayerPage), findsNothing);
|
|
|
|
await tester.tap(
|
|
find.byKey(const Key('recommend-card-hits-the-signal-demo')),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(
|
|
tester.widget<PlayerPage>(find.byType(PlayerPage).last).homeMode,
|
|
isTrue,
|
|
);
|
|
});
|
|
|
|
testWidgets('should_render_new_feed_structure_with_formatted_counts', (
|
|
tester,
|
|
) async {
|
|
const drama = Drama(
|
|
id: 'feed-drama',
|
|
title: 'Feed Drama',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
genre: 'Romance',
|
|
category: 'Urban',
|
|
totalEpisodes: 8,
|
|
freeEpisodes: 8,
|
|
viewCount: 419000,
|
|
likeCount: 1006,
|
|
favoriteCount: 32000,
|
|
commentCount: 12,
|
|
);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: drama,
|
|
episode: const Episode(
|
|
id: 'feed-episode',
|
|
number: 2,
|
|
title: 'Ignored Episode Title',
|
|
isFree: true,
|
|
),
|
|
controller: null,
|
|
locked: false,
|
|
liked: true,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
likeCount: 1006,
|
|
favoriteCount: 32000,
|
|
commentCount: 12,
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onMore: () {},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
tester.widget<Text>(find.byKey(const Key('home-feed-title'))).data,
|
|
'Feed Drama',
|
|
);
|
|
expect(find.byKey(const Key('home-feed-info-card')), findsNothing);
|
|
expect(find.byKey(const Key('home-feed-full-series')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-feed-tags')), findsOneWidget);
|
|
expect(find.text('Episode 2'), findsOneWidget);
|
|
expect(find.textContaining('41.9万'), findsOneWidget);
|
|
expect(
|
|
tester.widget<Text>(find.byKey(const Key('rail-like-count'))).data,
|
|
'1006',
|
|
);
|
|
expect(
|
|
tester.widget<Text>(find.byKey(const Key('rail-save-count'))).data,
|
|
'3.2万',
|
|
);
|
|
expect(
|
|
tester.widget<Text>(find.byKey(const Key('rail-comments-count'))).data,
|
|
'12',
|
|
);
|
|
String railAsset(Key key) {
|
|
final image = tester.widget<Image>(
|
|
find.descendant(of: find.byKey(key), matching: find.byType(Image)),
|
|
);
|
|
return (image.image as AssetImage).assetName;
|
|
}
|
|
|
|
expect(railAsset(const Key('rail-save')), 'assets/icon/rail/rail_save.png');
|
|
expect(
|
|
railAsset(const Key('rail-comments')),
|
|
'assets/icon/rail/rail_comment.png',
|
|
);
|
|
expect(railAsset(const Key('rail-like')), 'assets/icon/rail/rail_like.png');
|
|
expect(
|
|
railAsset(const Key('rail-share')),
|
|
'assets/icon/rail/rail_share.png',
|
|
);
|
|
expect(
|
|
tester
|
|
.widget<Image>(
|
|
find.descendant(
|
|
of: find.byKey(const Key('rail-share')),
|
|
matching: find.byType(Image),
|
|
),
|
|
)
|
|
.colorBlendMode,
|
|
BlendMode.srcIn,
|
|
);
|
|
expect(find.byKey(const Key('progress-loading')), findsNothing);
|
|
expect(
|
|
find.byKey(const Key('home-feed-progress-inactive')),
|
|
findsOneWidget,
|
|
);
|
|
expect(find.byKey(const Key('home-feed-progress-thumb')), findsNothing);
|
|
});
|
|
|
|
testWidgets('should_show_static_track_without_seek_when_feed_is_locked', (
|
|
tester,
|
|
) async {
|
|
var scrubStarts = 0;
|
|
var seeks = 0;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'locked-feed',
|
|
title: 'Locked Feed',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
),
|
|
episode: const Episode(
|
|
id: 'locked-feed-1',
|
|
number: 1,
|
|
title: 'Locked',
|
|
isFree: false,
|
|
locked: true,
|
|
),
|
|
controller: null,
|
|
locked: true,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onMore: () {},
|
|
onScrubStart: () => scrubStarts++,
|
|
onSeek: (_) => seeks++,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(const Key('progress-loading')), findsNothing);
|
|
expect(find.byKey(const Key('progress-loading-highlight')), findsNothing);
|
|
expect(
|
|
find.byKey(const Key('home-feed-progress-inactive')),
|
|
findsOneWidget,
|
|
);
|
|
expect(
|
|
tester
|
|
.getSize(find.byKey(const Key('home-feed-progress-inactive')))
|
|
.height,
|
|
2,
|
|
);
|
|
|
|
await tester.drag(
|
|
find.byKey(const Key('home-feed-progress')),
|
|
const Offset(120, 0),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(scrubStarts, 0);
|
|
expect(seeks, 0);
|
|
});
|
|
|
|
testWidgets('should_show_static_track_when_feed_video_is_uninitialized', (
|
|
tester,
|
|
) async {
|
|
final controller = ValueNotifier<VideoPlayerValue>(
|
|
const VideoPlayerValue.uninitialized(),
|
|
);
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'loading-feed',
|
|
title: 'Loading Feed',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
),
|
|
episode: const Episode(
|
|
id: 'loading-feed-1',
|
|
number: 1,
|
|
title: 'Loading',
|
|
isFree: true,
|
|
),
|
|
controller: controller,
|
|
locked: false,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onMore: () {},
|
|
onSeek: (_) {},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(const Key('progress-loading')), findsNothing);
|
|
expect(
|
|
find.byKey(const Key('home-feed-progress-inactive')),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
|
|
testWidgets('should_seek_and_open_player_from_feed_actions', (tester) async {
|
|
var opened = 0;
|
|
Duration? seeked;
|
|
final controller = ValueNotifier<VideoPlayerValue>(
|
|
VideoPlayerValue(
|
|
duration: const Duration(seconds: 100),
|
|
position: const Duration(seconds: 10),
|
|
isInitialized: true,
|
|
),
|
|
);
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'action-drama',
|
|
title: 'Action Drama',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
totalEpisodes: 8,
|
|
viewCount: 1200,
|
|
),
|
|
episode: const Episode(
|
|
id: 'action-episode',
|
|
number: 1,
|
|
title: 'Episode 1',
|
|
isFree: true,
|
|
),
|
|
controller: controller,
|
|
locked: false,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () => opened++,
|
|
onMore: () {},
|
|
onScrubStart: () {},
|
|
onSeek: (value) => seeked = value,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
final bar = tester.getRect(find.byKey(const Key('home-feed-full-series')));
|
|
expect(bar.height, 44);
|
|
expect(
|
|
tester
|
|
.widget<Container>(find.byKey(const Key('home-feed-full-series-bg')))
|
|
.color,
|
|
const Color(0x4D000000),
|
|
);
|
|
expect(
|
|
tester.getRect(find.textContaining('Watch full series')).center.dy,
|
|
closeTo(bar.center.dy, 2),
|
|
);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('home-feed-progress-thumb'))),
|
|
const Size(6, 6),
|
|
);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('home-feed-progress'))).height,
|
|
greaterThanOrEqualTo(24),
|
|
);
|
|
expect(
|
|
tester
|
|
.getRect(find.byKey(const Key('home-feed-progress-thumb')))
|
|
.center
|
|
.dy,
|
|
closeTo(
|
|
tester
|
|
.getRect(find.byKey(const Key('home-feed-progress-track')))
|
|
.center
|
|
.dy,
|
|
0.5,
|
|
),
|
|
);
|
|
|
|
final gesture = await tester.startGesture(
|
|
tester.getCenter(find.byKey(const Key('home-feed-progress'))),
|
|
);
|
|
await gesture.moveBy(const Offset(120, 0));
|
|
await tester.pump();
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('home-feed-progress-thumb'))),
|
|
const Size(14, 14),
|
|
);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('home-feed-progress-track'))).height,
|
|
6,
|
|
);
|
|
expect(
|
|
tester
|
|
.getRect(find.byKey(const Key('home-feed-progress-thumb')))
|
|
.center
|
|
.dy,
|
|
closeTo(
|
|
tester
|
|
.getRect(find.byKey(const Key('home-feed-progress-track')))
|
|
.center
|
|
.dy,
|
|
0.5,
|
|
),
|
|
);
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
expect(seeked, isNotNull);
|
|
expect(seeked!.inSeconds, greaterThan(0));
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('home-feed-progress-thumb'))),
|
|
const Size(6, 6),
|
|
);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('home-feed-progress-track'))).height,
|
|
2,
|
|
);
|
|
|
|
await tester.tap(find.byKey(const Key('home-feed-full-series')));
|
|
await tester.pump();
|
|
expect(opened, 1);
|
|
});
|
|
|
|
testWidgets('should_debounce_feed_loading_and_keep_track_while_scrubbing', (
|
|
tester,
|
|
) async {
|
|
final controller = ValueNotifier<VideoPlayerValue>(
|
|
const VideoPlayerValue(
|
|
duration: Duration(seconds: 100),
|
|
position: Duration(seconds: 10),
|
|
isInitialized: true,
|
|
),
|
|
);
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'debounce-drama',
|
|
title: 'Debounce Drama',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
totalEpisodes: 8,
|
|
),
|
|
episode: const Episode(
|
|
id: 'debounce-episode',
|
|
number: 1,
|
|
title: 'Episode 1',
|
|
isFree: true,
|
|
),
|
|
controller: controller,
|
|
locked: false,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onMore: () {},
|
|
onSeek: (_) {},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
controller.value = const VideoPlayerValue(
|
|
duration: Duration(seconds: 100),
|
|
position: Duration(seconds: 10),
|
|
isInitialized: true,
|
|
isBuffering: true,
|
|
);
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
expect(find.byKey(const Key('home-feed-progress-thumb')), findsOneWidget);
|
|
expect(find.byKey(const Key('progress-loading')), findsNothing);
|
|
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
expect(find.byKey(const Key('home-feed-progress-thumb')), findsNothing);
|
|
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
|
|
|
|
controller.value = const VideoPlayerValue(
|
|
duration: Duration(seconds: 100),
|
|
position: Duration(seconds: 10),
|
|
isInitialized: true,
|
|
);
|
|
await tester.pump();
|
|
expect(find.byKey(const Key('home-feed-progress-thumb')), findsOneWidget);
|
|
|
|
final gesture = await tester.startGesture(
|
|
tester.getCenter(find.byKey(const Key('home-feed-progress'))),
|
|
);
|
|
await gesture.moveBy(const Offset(60, 0));
|
|
await tester.pump();
|
|
controller.value = const VideoPlayerValue(
|
|
duration: Duration(seconds: 100),
|
|
position: Duration(seconds: 10),
|
|
isInitialized: true,
|
|
isBuffering: true,
|
|
);
|
|
await tester.pump(const Duration(milliseconds: 400));
|
|
|
|
expect(find.byKey(const Key('home-feed-progress-thumb')), findsOneWidget);
|
|
expect(find.byKey(const Key('progress-loading')), findsNothing);
|
|
|
|
controller.value = const VideoPlayerValue(
|
|
duration: Duration(seconds: 100),
|
|
position: Duration(seconds: 10),
|
|
isInitialized: true,
|
|
);
|
|
await tester.pump();
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('should_show_refresh_spinner_until_refresh_finishes', (
|
|
tester,
|
|
) async {
|
|
final completer = Completer<bool>();
|
|
var calls = 0;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedHeader(
|
|
l10n: AppLocalizations.of(context)!,
|
|
channel: HomeFeedChannel.recommend,
|
|
onChannelSelected: (_) {},
|
|
onRefresh: () {
|
|
calls++;
|
|
return completer.future;
|
|
},
|
|
onSearch: () {},
|
|
onMore: () {},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.byKey(const Key('home-feed-refresh')));
|
|
await tester.pump();
|
|
expect(find.byKey(const Key('home-feed-refreshing')), findsOneWidget);
|
|
|
|
await tester.tap(find.byKey(const Key('home-feed-refresh')));
|
|
await tester.pump();
|
|
expect(calls, 1);
|
|
|
|
completer.complete(true);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const Key('home-feed-refreshing')), findsNothing);
|
|
expect(find.byIcon(Icons.refresh_rounded), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('should_show_scrub_preview_card_from_home_progress', (
|
|
tester,
|
|
) async {
|
|
final controller = ValueNotifier<VideoPlayerValue>(
|
|
const VideoPlayerValue(
|
|
duration: Duration(seconds: 100),
|
|
position: Duration(seconds: 10),
|
|
isInitialized: true,
|
|
),
|
|
);
|
|
final service = _nullThumbnailService();
|
|
addTearDown(controller.dispose);
|
|
addTearDown(service.dispose);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'preview-drama',
|
|
title: 'Preview Drama',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
totalEpisodes: 8,
|
|
),
|
|
episode: const Episode(
|
|
id: 'preview-episode',
|
|
number: 1,
|
|
title: 'Episode 1',
|
|
isFree: true,
|
|
),
|
|
controller: controller,
|
|
locked: false,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
thumbnailService: service,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onMore: () {},
|
|
onScrubStart: () {},
|
|
onSeek: (_) {},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
final gesture = await tester.startGesture(
|
|
tester.getCenter(find.byKey(const Key('home-feed-progress'))),
|
|
);
|
|
await gesture.moveBy(const Offset(60, 0));
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(const Key('scrub-preview-card')), findsOneWidget);
|
|
expect(find.byKey(const Key('scrub-preview-poster')), findsOneWidget);
|
|
expect(find.textContaining('/ 01:40'), findsOneWidget);
|
|
|
|
await gesture.up();
|
|
await tester.pump();
|
|
expect(find.byKey(const Key('scrub-preview-card')), findsNothing);
|
|
});
|
|
|
|
testWidgets('should_seek_from_series_bar_when_overlay_is_cleared', (
|
|
tester,
|
|
) async {
|
|
Duration? seeked;
|
|
final controller = ValueNotifier<VideoPlayerValue>(
|
|
VideoPlayerValue(
|
|
duration: const Duration(seconds: 100),
|
|
position: const Duration(seconds: 10),
|
|
isInitialized: true,
|
|
),
|
|
);
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: AppTheme.light(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'clear-drama',
|
|
title: 'Clear Drama',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
totalEpisodes: 8,
|
|
),
|
|
episode: const Episode(
|
|
id: 'clear-episode',
|
|
number: 1,
|
|
title: 'Episode 1',
|
|
isFree: true,
|
|
),
|
|
controller: controller,
|
|
locked: false,
|
|
liked: false,
|
|
saved: false,
|
|
visible: false,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onMore: () {},
|
|
onScrubStart: () {},
|
|
onSeek: (value) => seeked = value,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('home-feed-full-series')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-feed-progress')), findsOneWidget);
|
|
|
|
final gesture = await tester.startGesture(
|
|
tester.getCenter(find.byKey(const Key('home-feed-progress'))),
|
|
);
|
|
await gesture.moveBy(const Offset(80, 0));
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(seeked, isNotNull);
|
|
expect(seeked!.inSeconds, greaterThan(0));
|
|
});
|
|
}
|
|
|
|
PlaybackThumbnailService _nullThumbnailService() {
|
|
return PlaybackThumbnailService(
|
|
frameLoader: _NullThumbnailLoader(),
|
|
sourceResolver: (_) =>
|
|
const PlaybackThumbnailSource(remoteUrl: 'https://example/video.mp4'),
|
|
prefetchDelay: const Duration(hours: 1),
|
|
);
|
|
}
|
|
|
|
class _NullThumbnailLoader implements PlaybackThumbnailFrameLoader {
|
|
@override
|
|
Future<ByteData?> load(PlaybackThumbnailFrameRequest request) async => null;
|
|
|
|
@override
|
|
void dispose() {}
|
|
}
|