// Author: fruit.com.cn // 职责:验证三种顶部导航接入稳定文字过渡并保留点击与选中语义。 import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/core/data/models/content_category.dart'; import 'package:fruitshorts/core/widgets/animated_nav_label.dart'; import 'package:fruitshorts/l10n/app_localizations.dart'; import 'package:fruitshorts/pages/home/widgets/home_grid_header.dart'; import 'package:fruitshorts/pages/recommend/recommend_types.dart'; import 'package:fruitshorts/pages/recommend/widgets/recommend_channel_nav.dart'; import 'package:fruitshorts/pages/recommend/widgets/recommend_top_nav.dart'; const _midpoint = Duration(milliseconds: 90); const _duration = Duration(milliseconds: 180); const _categories = [ ContentCategory(id: 'featured', name: '精选'), ContentCategory(id: 'new', name: '新剧'), ]; const _shortcuts = [ HomeGridCategoryShortcut( label: '精选', categoryName: 'featured', categoryId: 'featured', tab: HomePrimaryTab.featured, ), HomeGridCategoryShortcut( label: '新剧', categoryName: 'new', categoryId: 'new', tab: HomePrimaryTab.newReleases, ), ]; Widget _host(Widget child) => MaterialApp( locale: const Locale('zh'), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: Scaffold(body: child), ); double _scale(WidgetTester tester, Finder label) { return tester .widget( find.descendant(of: label, matching: find.byType(Transform)), ) .transform .entry(0, 0); } Future _verifyTransition( WidgetTester tester, Widget Function(bool) build, ) async { await tester.pumpWidget(_host(build(true))); await tester.pumpAndSettle(); final labels = find.byType(AnimatedNavLabel); final rects = [tester.getRect(labels.at(0)), tester.getRect(labels.at(1))]; await tester.pumpWidget(_host(build(false))); await tester.pump(_midpoint); expect(_scale(tester, labels.at(0)), inExclusiveRange(0.9, 1.0)); expect(_scale(tester, labels.at(1)), inExclusiveRange(0.9, 1.0)); expect(tester.getRect(labels.at(0)), rects[0]); expect(tester.getRect(labels.at(1)), rects[1]); await tester.pump(_duration); expect(tester.getRect(labels.at(1)), rects[1]); final semantics = tester.widget( find.descendant(of: labels.at(1), matching: find.byType(Semantics)).first, ); expect(semantics.properties.selected, isTrue); } void main() { testWidgets('should_keep_channel_labels_regular_when_selection_changes', ( tester, ) async { const categories = [ ContentCategory(id: 'featured', name: '精选'), ContentCategory(id: 'weekly', name: '本周必看'), ]; for (final selected in categories) { await tester.pumpWidget( _host( RecommendChannelNav( categories: categories, selectedId: selected.id, onSelected: (_) {}, onSearch: () {}, ), ), ); await tester.pumpAndSettle(); for (final category in categories) { final text = tester.widget(find.text(category.name)); expect(text.style?.fontWeight, FontWeight.w400); expect(text.style?.fontSize, 17); } expect(tester.takeException(), isNull); } }); testWidgets('should_keep_home_labels_stable_when_category_changes', ( tester, ) async { int? tapped; HomeGridHeader header(bool first) => HomeGridHeader( callbacks: HomeGridCallbacks( onSearch: () {}, onOpenVip: () {}, onOpenWallet: () {}, onOpenFilter: () {}, ), categories: _shortcuts, selectedIndex: first ? 0 : 1, onSectionSelected: (index) => tapped = index, ); await _verifyTransition(tester, header); await tester.tap(find.byKey(const Key('home-primary-label-new'))); expect(tapped, 1); }); testWidgets('should_keep_inner_nav_labels_stable_when_tab_changes', ( tester, ) async { RecommendInnerTab? tapped; RecommendTopNav nav(bool first) => RecommendTopNav( selected: first ? RecommendInnerTab.feed : RecommendInnerTab.playlists, onSelected: (tab) => tapped = tab, onSearch: () {}, ); await _verifyTransition(tester, nav); await tester.tap(find.byKey(const Key('recommend-tab-playlist'))); expect(tapped, RecommendInnerTab.playlists); }); testWidgets('should_keep_channel_labels_stable_when_selection_changes', ( tester, ) async { String? tapped; RecommendChannelNav nav(bool first) => RecommendChannelNav( categories: _categories, selectedId: first ? 'featured' : 'new', onSelected: (id) => tapped = id, onSearch: () {}, ); await _verifyTransition(tester, nav); await tester.tap(find.byKey(const Key('recommend-tab-new'))); expect(tapped, 'new'); }); }