Files
ReelShort/test/following/following_page_test.dart
T

392 lines
14 KiB
Dart

// Author: fruit.com.cn
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/models/watch_progress.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_colors.dart';
import 'package:fruitshorts/core/theme/app_dimens.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 '../support/fake_catalog.dart';
import '../support/fake_category.dart';
import '../support/fake_interaction_repositories.dart';
import '../support/widget_player.dart';
void main() {
testWidgets('should_render_following_tabs_grid_and_edit_actions', (
tester,
) async {
_signIn();
final catalog = FakeCatalogRepository();
await tester.pumpWidget(
_app(
catalog: catalog,
favorites: InMemoryFavoriteRepository(
cards: catalog.dramas.take(1).toList(),
saved: {catalog.dramas.first.id},
),
),
);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('following-page')), findsOneWidget);
expect(find.byKey(const Key('following-tab-favorites')), findsOneWidget);
expect(find.byKey(const Key('following-tab-history')), findsOneWidget);
expect(find.byKey(const Key('following-tab-reserve')), findsNothing);
expect(find.byKey(const Key('following-favorites-grid')), findsOneWidget);
expect(find.byKey(const Key('following-add-card')), findsOneWidget);
expect(find.byType(CustomScrollView), findsWidgets);
final tab = tester.widget<AnimatedDefaultTextStyle>(
find.descendant(
of: find.byKey(const Key('following-tab-favorites')),
matching: find.byType(AnimatedDefaultTextStyle),
),
);
expect(tab.style.fontSize, AppDimens.followingTabFont);
expect(tab.style.fontWeight, FontWeight.w600);
expect(tab.style.color, AppColors.textPrimary);
final editIcon = tester.widget<Icon>(find.byIcon(Icons.edit_outlined));
expect(editIcon.size, AppDimens.followingEditIconSize);
expect(editIcon.color, AppColors.textTabInactive);
final grid = tester.widget<SliverGrid>(
find.descendant(
of: find.byKey(const Key('following-favorites-grid')),
matching: find.byType(SliverGrid),
),
);
final delegate =
grid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
expect(delegate.crossAxisCount, 3);
expect(delegate.crossAxisSpacing, AppDimens.followingGridGap);
expect(delegate.mainAxisSpacing, AppDimens.followingGridRowGap);
expect(delegate.mainAxisExtent, greaterThan(0));
final card = find.byKey(const Key('following-card-the-signal-demo'));
final coverFinder = find.byKey(
const Key('following-cover-the-signal-demo'),
);
final cover = tester.widget<AspectRatio>(coverFinder);
expect(cover.aspectRatio, AppDimens.cardCoverAspectRatio);
final coverClip = tester.widget<ClipRRect>(
find.descendant(
of: find.byKey(const Key('following-cover-the-signal-demo')),
matching: find.byType(ClipRRect),
),
);
expect(
coverClip.borderRadius,
BorderRadius.circular(AppDimens.homeCardRadius),
);
final titleFinder = find.descendant(
of: card,
matching: find.text('The Signal'),
);
final title = tester.widget<Text>(titleFinder);
expect(title.style?.fontSize, AppDimens.cardTitleFont);
expect(title.style?.fontWeight, FontWeight.w500);
expect(title.style?.height, AppDimens.cardTitleLineHeight);
final views = tester.widget<Text>(
find.descendant(
of: find.byKey(const Key('following-views-the-signal-demo')),
matching: find.byType(Text),
),
);
expect(views.style?.fontSize, AppDimens.cardPlayCountFont);
expect(views.style?.fontWeight, FontWeight.w400);
expect(
find.descendant(
of: coverFinder,
matching: find.byKey(const Key('following-views-the-signal-demo')),
),
findsOneWidget,
);
expect(views.style?.color, AppColors.textPrimary);
expect(
find.descendant(
of: find.byKey(const Key('following-views-the-signal-demo')),
matching: find.byIcon(Icons.local_fire_department_rounded),
),
findsOneWidget,
);
expect(
tester.getTopLeft(titleFinder).dx,
tester.getTopLeft(coverFinder).dx,
);
expect(
tester.getTopLeft(card).dx,
lessThan(
tester.getTopLeft(find.byKey(const Key('following-add-card'))).dx,
),
);
await tester.tap(find.byKey(const Key('following-edit')));
await tester.pumpAndSettle();
expect(
find.byKey(const Key('following-remove-the-signal-demo')),
findsOneWidget,
);
await tester.tap(find.byKey(const Key('following-remove-the-signal-demo')));
await tester.pumpAndSettle();
expect(find.byType(AlertDialog), findsOneWidget);
await tester.tap(
find.descendant(
of: find.byType(AlertDialog),
matching: find.byType(FilledButton),
),
);
await tester.pumpAndSettle();
expect(
find.byKey(const Key('following-remove-the-signal-demo')),
findsNothing,
);
expect(find.byIcon(Icons.edit_outlined), findsOneWidget);
expect(
find.byKey(const Key('following-card-the-signal-demo')),
findsNothing,
);
await tester.tap(find.byKey(const Key('following-tab-history')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('following-history-empty')), findsOneWidget);
});
testWidgets('should_show_auth_gate_when_signed_out', (tester) async {
SharedPreferencesAsyncPlatform.instance =
InMemorySharedPreferencesAsync.empty();
await tester.pumpWidget(_app(catalog: FakeCatalogRepository()));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('auth-gate-panel')), findsOneWidget);
expect(find.byKey(const Key('following-favorites-grid')), findsNothing);
});
testWidgets('should_show_empty_favorites_and_history', (tester) async {
_signIn();
await tester.pumpWidget(_app(catalog: FakeCatalogRepository()));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('following-add-card')), findsOneWidget);
expect(find.byKey(const Key('following-favorites-empty')), findsNothing);
await tester.tap(find.byKey(const Key('following-tab-history')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('following-history-empty')), findsOneWidget);
});
testWidgets('should_render_history_metadata_without_detail_fetch', (
tester,
) async {
_signIn();
final catalog = _CountingCatalogRepository();
await tester.pumpWidget(
_app(
catalog: catalog,
history: InMemoryWatchHistoryRepository(
seed: [
WatchProgress(
dramaId: 'the-signal-demo',
episodeId: 'the-signal-demo-3',
dramaTitle: 'Server title',
dramaCover: '/files/server-cover.jpg',
episodeNumber: 3,
totalEpisodes: 8,
position: const Duration(seconds: 25),
duration: const Duration(seconds: 100),
),
],
),
),
);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('following-tab-history')));
await tester.pumpAndSettle();
expect(find.text('Server title'), findsOneWidget);
expect(find.text('Episode 3 / 8 total'), findsOneWidget);
expect(find.text('Watched 25%'), findsOneWidget);
expect(
find.byKey(const Key('following-history-card-the-signal-demo')),
findsOneWidget,
);
expect(
find.byKey(const Key('following-history-continue-the-signal-demo')),
findsOneWidget,
);
expect(
find.byKey(const Key('following-progress-the-signal-demo')),
findsOneWidget,
);
final cover = tester.widget<SizedBox>(
find.byKey(const Key('following-history-cover-the-signal-demo')),
);
expect(cover.width, AppDimens.followingHistoryCoverWidth);
expect(cover.height, AppDimens.followingHistoryCoverHeight);
final historyGrid = tester.widget<SliverGrid>(
find.descendant(
of: find.byKey(const Key('following-history-grid')),
matching: find.byType(SliverGrid),
),
);
final historyDelegate =
historyGrid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
expect(historyDelegate.crossAxisCount, 1);
expect(historyDelegate.mainAxisSpacing, AppDimens.followingHistoryRowGap);
expect(catalog.detailFetches, 0);
await tester.tap(find.byKey(const Key('following-edit')));
await tester.pumpAndSettle();
expect(
find.byKey(const Key('following-history-remove-the-signal-demo')),
findsOneWidget,
);
expect(
find.byKey(const Key('following-history-continue-the-signal-demo')),
findsNothing,
);
});
testWidgets('should_switch_following_pages_horizontally', (tester) async {
_signIn();
await tester.pumpWidget(_app(catalog: FakeCatalogRepository()));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
await tester.drag(
find.byKey(const Key('following-tab-pages')),
const Offset(-500, 0),
);
await tester.pumpAndSettle();
expect(find.byKey(const Key('following-history-empty')), findsOneWidget);
final historyTab = tester.widget<AnimatedDefaultTextStyle>(
find.descendant(
of: find.byKey(const Key('following-tab-history')),
matching: find.byType(AnimatedDefaultTextStyle),
),
);
expect(historyTab.style.fontWeight, FontWeight.w600);
expect(historyTab.style.color, AppColors.textPrimary);
});
testWidgets('should_open_home_from_add_card', (tester) async {
_signIn();
await tester.pumpWidget(_app(catalog: FakeCatalogRepository()));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('following-add-card')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-grid')), findsOneWidget);
});
testWidgets('should_reset_edit_state_when_switching_tabs', (tester) async {
_signIn();
final catalog = FakeCatalogRepository();
await tester.pumpWidget(
_app(
catalog: catalog,
favorites: InMemoryFavoriteRepository(
cards: catalog.dramas,
saved: catalog.dramas.map((drama) => drama.id).toSet(),
),
),
);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('following-edit')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('following-tab-history')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('following-tab-favorites')));
await tester.pumpAndSettle();
expect(
find.byKey(const Key('following-card-the-signal-demo')),
findsOneWidget,
);
expect(find.byIcon(Icons.edit_outlined), findsOneWidget);
});
testWidgets('should_fit_following_cards_on_compact_viewport', (tester) async {
tester.view.physicalSize = const Size(320, 640);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
_signIn();
final catalog = FakeCatalogRepository();
await tester.pumpWidget(
_app(
catalog: catalog,
favorites: InMemoryFavoriteRepository(
cards: catalog.dramas.take(1).toList(),
saved: {catalog.dramas.first.id},
),
),
);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-follow')));
await tester.pumpAndSettle();
expect(
find.byKey(const Key('following-card-the-signal-demo')),
findsOneWidget,
);
expect(tester.takeException(), isNull);
});
}
void _signIn() {
SharedPreferencesAsyncPlatform.instance =
InMemorySharedPreferencesAsync.withData({
'auth.accessToken': 'access',
'auth.refreshToken': 'refresh',
'auth.user': '{"uid":"9","nickname":"Viewer","avatarUrl":""}',
});
}
Widget _app({
required FakeCatalogRepository catalog,
FavoriteRepository? favorites,
WatchHistoryRepository? history,
}) {
return LumaDramaApp(
playerFactory: createWidgetPlayer,
catalogRepository: catalog,
categoryRepository: FakeCategoryRepository(catalog: catalog),
watchHistoryRepository: history ?? InMemoryWatchHistoryRepository(),
favoriteRepository: favorites ?? InMemoryFavoriteRepository(),
playbackRepository: FakePlaybackRepository(),
commentRepository: FakeCommentRepository(),
interactionRepository: FakeInteractionRepository(),
);
}
class _CountingCatalogRepository extends FakeCatalogRepository {
int detailFetches = 0;
@override
Future<Drama> fetchDrama(String dramaId) {
detailFetches += 1;
return super.fetchDrama(dramaId);
}
}