383 lines
12 KiB
Dart
383 lines
12 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'dart:async';
|
|
|
|
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/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/theme/app_theme.dart';
|
|
import 'package:fruitshorts/l10n/app_localizations.dart';
|
|
import 'package:fruitshorts/pages/player/widgets/home_feed_overlay.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_immersive_feed_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),
|
|
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-home')));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('home-feed-title')), findsOneWidget);
|
|
expect(find.byKey(const Key('home-feed-full-series')), findsOneWidget);
|
|
expect(find.byType(PageView), findsOneWidget);
|
|
expect(find.byKey(const Key('home-browse-page')), findsNothing);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
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,
|
|
liked: true,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
likeCount: 1006,
|
|
favoriteCount: 32000,
|
|
commentCount: 12,
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onEpisodes: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onRefreshFeed: () async => true,
|
|
onDownload: () {},
|
|
onClear: () {},
|
|
onSearch: () {},
|
|
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',
|
|
);
|
|
});
|
|
|
|
testWidgets('should_refresh_seek_and_open_player_from_feed_actions', (
|
|
tester,
|
|
) async {
|
|
var refreshed = 0;
|
|
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,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onEpisodes: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () => opened++,
|
|
onRefreshFeed: () async {
|
|
refreshed++;
|
|
return true;
|
|
},
|
|
onDownload: () {},
|
|
onClear: () {},
|
|
onSearch: () {},
|
|
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,
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.byKey(const Key('home-feed-refresh')));
|
|
await tester.pump();
|
|
expect(refreshed, 1);
|
|
|
|
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_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: HomeFeedOverlay(
|
|
l10n: AppLocalizations.of(context)!,
|
|
drama: const Drama(
|
|
id: 'refresh-drama',
|
|
title: 'Refresh Drama',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '',
|
|
totalEpisodes: 8,
|
|
),
|
|
episode: const Episode(
|
|
id: 'refresh-episode',
|
|
number: 1,
|
|
title: 'Episode 1',
|
|
isFree: true,
|
|
),
|
|
controller: null,
|
|
liked: false,
|
|
saved: false,
|
|
visible: true,
|
|
boosting: false,
|
|
onTogglePlay: () {},
|
|
onBoostStart: () {},
|
|
onBoostEnd: () {},
|
|
onLike: () {},
|
|
onSave: () {},
|
|
onComments: () {},
|
|
onShare: () {},
|
|
onEpisodes: () {},
|
|
onDetail: () {},
|
|
onOpenFullPlayer: () {},
|
|
onRefreshFeed: () {
|
|
calls++;
|
|
return completer.future;
|
|
},
|
|
onDownload: () {},
|
|
onClear: () {},
|
|
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);
|
|
});
|
|
}
|