237 lines
8.6 KiB
Dart
237 lines
8.6 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:fruitshorts/core/data/models/drama.dart';
|
|
import 'package:fruitshorts/core/data/repositories/comment_repository.dart';
|
|
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
|
|
import 'package:fruitshorts/core/data/repositories/interaction_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/catalog_controller.dart';
|
|
import 'package:fruitshorts/core/data/services/favorite_controller.dart';
|
|
import 'package:fruitshorts/core/data/services/interaction_controller.dart';
|
|
import 'package:fruitshorts/core/data/services/playback_session.dart';
|
|
import 'package:fruitshorts/core/platform/haptics.dart';
|
|
import 'package:fruitshorts/core/theme/app_theme.dart';
|
|
import 'package:fruitshorts/l10n/app_localizations.dart';
|
|
import 'package:fruitshorts/pages/drama_detail/drama_detail_view.dart';
|
|
import 'package:fruitshorts/pages/player/player_view.dart';
|
|
|
|
import '../support/fake_catalog.dart';
|
|
import '../support/fake_haptics.dart';
|
|
import '../support/fake_interaction_repositories.dart';
|
|
import '../support/widget_player.dart';
|
|
|
|
void main() {
|
|
testWidgets('should_render_preview_hero_cta_synopsis_and_episode_chips', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(390, 844);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(_host(_detailDrama()));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(tester.getSize(find.byKey(const Key('detail-hero'))).height, 190);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('detail-back'))),
|
|
const Size(36, 36),
|
|
);
|
|
expect(
|
|
tester
|
|
.widget<Icon>(
|
|
find.descendant(
|
|
of: find.byKey(const Key('detail-back')),
|
|
matching: find.byType(Icon),
|
|
),
|
|
)
|
|
.size,
|
|
18,
|
|
);
|
|
expect(find.byKey(const Key('detail-cta')), findsOneWidget);
|
|
expect(tester.getSize(find.byKey(const Key('detail-cta'))).height, 40);
|
|
expect(find.byKey(const Key('detail-episode-chip-1')), findsOneWidget);
|
|
expect(find.byKey(const Key('detail-episode-chip-8')), findsOneWidget);
|
|
|
|
final synopsis = tester.widget<Text>(
|
|
find.byKey(const Key('detail-synopsis')),
|
|
);
|
|
expect(synopsis.style?.fontSize, 11);
|
|
expect(synopsis.style?.height, 1.6);
|
|
|
|
await tester.tap(find.byKey(const Key('detail-more')));
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const Key('detail-favorite')), findsOneWidget);
|
|
expect(find.byKey(const Key('detail-download')), findsOneWidget);
|
|
expect(find.byKey(const Key('detail-share')), findsOneWidget);
|
|
expect(find.byKey(const Key('detail-report')), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('should_fit_compact_viewport_when_detail_scrolls', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(320, 568);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(_host(_detailDrama()));
|
|
await tester.pumpAndSettle();
|
|
final grid = tester.widget<GridView>(
|
|
find.byKey(const Key('detail-episode-chips')),
|
|
);
|
|
expect(
|
|
(grid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount)
|
|
.crossAxisCount,
|
|
6,
|
|
);
|
|
await tester.drag(
|
|
find.byKey(const Key('detail-scroll')),
|
|
const Offset(0, -520),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('detail-episode-chip-8')), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('should_render_sorted_six_column_grid_and_open_original_index', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(390, 844);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(_host(_detailDrama(count: 80)));
|
|
await tester.pumpAndSettle();
|
|
|
|
final grid = tester.widget<GridView>(
|
|
find.byKey(const Key('detail-episode-chips')),
|
|
);
|
|
final delegate =
|
|
grid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
|
|
expect(delegate.crossAxisCount, 6);
|
|
expect(delegate.mainAxisSpacing, 8);
|
|
expect(delegate.crossAxisSpacing, 8);
|
|
expect(delegate.childAspectRatio, closeTo(1.35, 0.001));
|
|
|
|
final chip1 = find.byKey(const Key('detail-episode-chip-1'));
|
|
final chip2 = find.byKey(const Key('detail-episode-chip-2'));
|
|
final chip6 = find.byKey(const Key('detail-episode-chip-6'));
|
|
final chip7 = find.byKey(const Key('detail-episode-chip-7'));
|
|
expect(tester.getTopLeft(chip1).dy, tester.getTopLeft(chip6).dy);
|
|
expect(
|
|
tester.getTopLeft(chip7).dy,
|
|
greaterThan(tester.getTopLeft(chip1).dy),
|
|
);
|
|
expect(tester.getTopLeft(chip1).dx, lessThan(tester.getTopLeft(chip2).dx));
|
|
expect(tester.getSize(chip1), tester.getSize(chip2));
|
|
|
|
await tester.drag(
|
|
find.byKey(const Key('detail-scroll')),
|
|
const Offset(0, -420),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
final chip12 = find.byKey(const Key('detail-episode-chip-12'));
|
|
expect(chip12, findsOneWidget);
|
|
await tester.tap(chip12);
|
|
await tester.pumpAndSettle();
|
|
|
|
final player = tester.widget<PlayerPage>(find.byType(PlayerPage));
|
|
expect(player.initialIndex, 11);
|
|
});
|
|
|
|
testWidgets('should_sort_episode_chips_ascending_by_number', (tester) async {
|
|
tester.view.physicalSize = const Size(390, 844);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(_host(_detailDrama(count: 80, descending: true)));
|
|
await tester.pumpAndSettle();
|
|
|
|
final chip1 = find.byKey(const Key('detail-episode-chip-1'));
|
|
final chip2 = find.byKey(const Key('detail-episode-chip-2'));
|
|
final chip6 = find.byKey(const Key('detail-episode-chip-6'));
|
|
final chip7 = find.byKey(const Key('detail-episode-chip-7'));
|
|
expect(tester.getTopLeft(chip1).dy, tester.getTopLeft(chip6).dy);
|
|
expect(tester.getTopLeft(chip1).dx, lessThan(tester.getTopLeft(chip2).dx));
|
|
expect(
|
|
tester.getTopLeft(chip7).dy,
|
|
greaterThan(tester.getTopLeft(chip1).dy),
|
|
);
|
|
expect(tester.getSize(chip1), tester.getSize(chip2));
|
|
});
|
|
}
|
|
|
|
Widget _host(Drama drama) {
|
|
final catalog = FakeCatalogRepository(dramas: [drama]);
|
|
final interactions = FakeInteractionRepository();
|
|
return MultiProvider(
|
|
providers: [
|
|
Provider<WatchHistoryRepository>.value(
|
|
value: InMemoryWatchHistoryRepository(),
|
|
),
|
|
Provider<PlaybackRepository>.value(value: FakePlaybackRepository()),
|
|
Provider<PlayerFactory>.value(value: createWidgetPlayer),
|
|
Provider(create: (_) => PlaybackCoordinator()),
|
|
Provider<InteractionRepository>.value(value: interactions),
|
|
Provider<CommentRepository>.value(value: FakeCommentRepository()),
|
|
Provider<Haptics>.value(value: FakeHaptics()),
|
|
ChangeNotifierProvider(
|
|
create: (_) => FavoriteController(InMemoryFavoriteRepository()),
|
|
),
|
|
ChangeNotifierProvider(
|
|
create: (_) => InteractionController(interactions),
|
|
),
|
|
ChangeNotifierProvider(create: (_) => CatalogController(catalog)..load()),
|
|
],
|
|
child: MaterialApp(
|
|
theme: AppTheme.dark(),
|
|
locale: const Locale('en'),
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
home: DramaDetailPage(drama: drama),
|
|
),
|
|
);
|
|
}
|
|
|
|
Drama _detailDrama({int count = 8, bool descending = false}) {
|
|
final numbers = List<int>.generate(
|
|
count,
|
|
(index) => descending ? count - index : index + 1,
|
|
);
|
|
return Drama(
|
|
id: 'detail-k25',
|
|
title: 'Detail K25',
|
|
synopsis:
|
|
'She agreed to marry a mysterious stranger to save her family, '
|
|
'until she discovered his secret identity and the city he controls.',
|
|
posterUrl: '/files/detail-k25.png',
|
|
genre: 'Urban Romance',
|
|
category: 'Romance',
|
|
totalEpisodes: count,
|
|
viewCount: 4800000,
|
|
detailLoaded: true,
|
|
episodes: [
|
|
for (final number in numbers)
|
|
Episode(
|
|
id: 'detail-k25-$number',
|
|
number: number,
|
|
title: 'Episode $number',
|
|
isFree: number == 1,
|
|
durationSec: 135,
|
|
locked: number > 1,
|
|
videoUrl: number == 1 ? '/files/detail-k25-1.mp4' : '',
|
|
),
|
|
],
|
|
);
|
|
}
|