// 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/wallet.dart'; import 'package:fruitshorts/core/data/repositories/commerce_repository.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/widgets/app_bottom_nav.dart'; import 'package:fruitshorts/pages/following/following_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'; import '../support/fake_catalog.dart'; import '../support/fake_category.dart'; import '../support/fake_haptics.dart'; import '../support/fake_interaction_repositories.dart'; import '../support/widget_player.dart'; const _keys = [ Key('home-tabs-bar'), Key('tab-home'), Key('tab-recommend'), Key('tab-follow'), Key('tab-mine'), ]; void main() { setUp(() { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.withData({ 'auth.accessToken': 'test-access', 'auth.refreshToken': 'test-refresh', 'auth.user': '{"uid":"9","nickname":"Viewer","avatarUrl":""}', }); }); testWidgets('should_theme_four_tabs_and_switch_selected_state_when_tapped', ( tester, ) async { final haptics = FakeHaptics(); await _pumpApp(tester, haptics); haptics.reset(); for (final key in _keys) { expect(find.byKey(key), findsOneWidget); } expect(find.byKey(const Key('home-wallet-entry')), findsOneWidget); expect(find.byKey(const Key('home-wallet-badge')), findsOneWidget); expect(find.byKey(const Key('mine-mini-player')), findsNothing); expect(find.byType(FloatingActionButton), findsNothing); for (final key in _keys.skip(1)) { expect(tester.getSize(find.byKey(key)).height, greaterThanOrEqualTo(48)); } final tabCenters = _keys .skip(1) .map((key) => tester.getCenter(find.byKey(key)).dx) .toList(); expect(tabCenters, orderedEquals(tabCenters.toList()..sort())); expect( find.descendant( of: find.byKey(const Key('tab-home')), matching: find.text('Home'), ), findsOneWidget, ); expect( find.descendant( of: find.byKey(const Key('tab-recommend')), matching: find.text('Recommend'), ), findsOneWidget, ); expect( find.descendant( of: find.byKey(const Key('tab-follow')), matching: find.text('Following'), ), findsOneWidget, ); expect( find.descendant( of: find.byKey(const Key('tab-mine')), matching: find.text('My'), ), findsOneWidget, ); final barFinder = find.byKey(const Key('home-tabs-bar')); final bar = tester.widget(barFinder); expect(bar.color, AppColors.navBackground); expect(bar.decoration, isNull); expect( tester .widget( find.descendant( of: find.byKey(const Key('tab-recommend')), matching: find.text('Recommend'), ), ) .style ?.color, AppColors.navUnselected, ); expect( tester .widget( find.descendant( of: find.byKey(const Key('tab-home')), matching: find.byType(AnimatedScale), ), ) .duration, lessThanOrEqualTo(const Duration(milliseconds: 200)), ); expect( find.descendant( of: find.byKey(const Key('tab-home')), matching: find.byIcon(Icons.home_rounded), ), findsOneWidget, ); expect( find.descendant( of: find.byKey(const Key('tab-recommend')), matching: find.byIcon(Icons.smart_display_outlined), ), findsOneWidget, ); expect( find.descendant( of: find.byKey(const Key('tab-follow')), matching: find.byIcon(Icons.bookmark_border_rounded), ), findsOneWidget, ); expect( find.descendant( of: find.byKey(const Key('tab-mine')), matching: find.byIcon(Icons.person_outline_rounded), ), findsOneWidget, ); expect( tester .widget( find.descendant( of: find.byKey(const Key('tab-home')), matching: find.byIcon(Icons.home_rounded), ), ) .color, AppColors.navSelected, ); await tester.tap(find.byKey(const Key('tab-recommend'))); await tester.pumpAndSettle(); expect(haptics.selectionClicks, 1); final theaterBar = tester.widget(barFinder); expect(theaterBar.color, AppColors.navBackground); expect(theaterBar.decoration, isNull); await tester.tap(find.byKey(const Key('tab-recommend'))); await tester.pumpAndSettle(); expect(haptics.selectionClicks, 1); expect( find.descendant( of: find.byKey(const Key('tab-recommend')), matching: find.byIcon(Icons.smart_display_rounded), ), findsOneWidget, ); expect( tester .widget( find.descendant( of: find.byKey(const Key('tab-recommend')), matching: find.text('Recommend'), ), ) .style ?.color, AppColors.navSelected, ); expect( tester .widget( find.descendant( of: find.byKey(const Key('tab-home')), matching: find.text('Home'), ), ) .style ?.color, AppColors.navUnselected, ); expect( find.descendant( of: find.byKey(const Key('tab-home')), matching: find.byIcon(Icons.home_outlined), ), findsOneWidget, ); }); testWidgets('should_map_four_tabs_to_home_recommend_following_and_me', ( tester, ) async { await _pumpApp(tester); expect(find.byKey(const Key('tab-home')), findsOneWidget); expect(find.byKey(const Key('tab-recommend')), findsOneWidget); expect(find.byKey(const Key('tab-follow')), findsOneWidget); expect(find.byKey(const Key('tab-mine')), findsOneWidget); expect(find.byKey(const Key('tab-create')), findsNothing); expect(find.byKey(const Key('home-grid')), findsOneWidget); await tester.tap(find.byKey(const Key('tab-recommend'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('recommend-page')), findsOneWidget); _expectNoFloatingOverlays(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); final favorites = find.byType(FollowingPage); expect(favorites, findsOneWidget); expect(find.byKey(const Key('following-page')), findsOneWidget); expect(find.byType(AppBottomNav), findsOneWidget); expect( find.descendant(of: favorites, matching: find.byType(Scaffold)), findsNothing, ); expect(Navigator.canPop(tester.element(favorites)), isFalse); _expectNoFloatingOverlays(); expect( find.descendant( of: find.byKey(const Key('tab-follow')), matching: find.byIcon(Icons.bookmark_rounded), ), findsOneWidget, ); await tester.tap(find.byKey(const Key('tab-mine'))); await tester.pumpAndSettle(); expect(find.text('Viewer'), findsOneWidget); expect(find.byKey(const Key('mine-menu')), findsOneWidget); expect(find.byKey(const Key('mine-wallet')), findsOneWidget); expect(find.byKey(const Key('mine-edit')), findsOneWidget); expect(find.byKey(const Key('mine-library-tab-0')), findsNothing); _expectNoFloatingOverlays(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); expect(favorites, findsOneWidget); expect(find.byType(AppBottomNav), findsOneWidget); expect(Navigator.canPop(tester.element(favorites)), isFalse); await tester.tap(find.byKey(const Key('tab-home'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('home-grid')), findsOneWidget); }); testWidgets('should_not_haptic_when_ordinary_list_item_is_opened', ( tester, ) async { final haptics = FakeHaptics(); await _pumpApp(tester, haptics); await tester.tap(find.byKey(const Key('tab-mine'))); await tester.pumpAndSettle(); haptics.reset(); await tester.ensureVisible(find.byKey(const Key('mine-settings'))); await tester.tap(find.byKey(const Key('mine-settings'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('settings-page')), findsOneWidget); expect(haptics.calls, isEmpty); }); } Future _pumpApp(WidgetTester tester, [FakeHaptics? haptics]) async { 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(), commerceRepository: const _WalletCommerceRepository(), haptics: haptics ?? FakeHaptics(), ), ); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-home'))); await tester.pumpAndSettle(); } class _WalletCommerceRepository implements CommerceRepository { const _WalletCommerceRepository(); @override Future fetchWallet() async { return const WalletSnapshot( wallet: CoinWallet( coinBalance: 320, totalRechargedCoin: 500, totalConsumedCoin: 180, totalRefundedCoin: 0, ), ); } @override Future unlock(String episodeId) async { return const UnlockResult( unlocked: true, accessType: 'UNLOCKED', coinCost: 0, coinBalance: 320, ); } } void _expectNoFloatingOverlays() { expect(find.byKey(const Key('mine-mini-player')), findsNothing); expect(find.byType(FloatingActionButton), findsNothing); }