Files
ReelShort/test/drama_detail/drama_detail_logic_test.dart
T

157 lines
4.3 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/data/models/drama.dart';
import 'package:fruitshorts/core/data/remote/api_client.dart';
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
import 'package:fruitshorts/core/data/services/favorite_controller.dart';
import 'package:fruitshorts/pages/drama_detail/drama_detail_logic.dart';
import '../support/fake_watch_history.dart';
/// 详情页逻辑依赖:票据仓库 + 收藏控制器(测试里都是内存实现)。
DramaDetailLogic _logic(
Drama drama,
FakeWatchHistory history, {
FavoriteController? favorites,
}) =>
DramaDetailLogic(
drama: drama,
history: history,
playback: FakePlaybackRepository(),
favorites: favorites ?? FavoriteController(InMemoryFavoriteRepository()),
);
Drama _card(String id) => Drama(
id: id,
title: id,
synopsis: 'synopsis',
posterUrl: '/files/$id.jpg',
totalEpisodes: 3,
episodes: [
Episode(
id: '$id-1',
number: 1,
title: '第 1 集',
isFree: true,
videoUrl: '/files/$id-1.mp4',
),
],
);
Drama _detail(String id) => Drama(
id: id,
title: id,
synopsis: 'synopsis',
posterUrl: '/files/$id.jpg',
totalEpisodes: 3,
detailLoaded: true,
episodes: [
for (var number = 1; number <= 3; number++)
Episode(
id: '$id-$number',
number: number,
title: '第 $number 集',
isFree: true,
videoUrl: '/files/$id-$number.mp4',
),
],
);
void main() {
test('should_upgrade_to_full_episode_list_when_detail_loads_for_list_card', () async {
var calls = 0;
final logic = _logic(_card('signal'), FakeWatchHistory());
await logic.load(() async {
calls++;
return _detail('signal');
});
expect(calls, 1);
expect(logic.loading, isFalse);
expect(logic.failed, isFalse);
expect(logic.drama.episodes, hasLength(3));
logic.dispose();
});
test('should_keep_card_and_report_reason_when_load_fails', () async {
final logic = _logic(_card('signal'), FakeWatchHistory());
await logic.load(() async => throw const ApiException(500, '服务异常'));
expect(logic.failed, isTrue);
expect(logic.failureMessage, '服务异常');
expect(logic.drama.episodes, hasLength(1));
await logic.load(() async => throw StateError('offline'));
expect(logic.failed, isTrue);
expect(logic.failureMessage, isNull);
logic.dispose();
});
test('should_skip_request_when_detail_is_already_loaded', () async {
var calls = 0;
final logic = _logic(_detail('signal'), FakeWatchHistory());
await logic.load(() async {
calls++;
return _detail('signal');
});
expect(calls, 0);
expect(logic.drama.episodes, hasLength(3));
logic.dispose();
});
test('should_adjust_favorite_count_only_after_successful_changes', () async {
final repository = InMemoryFavoriteRepository(cards: [_favoriteDrama]);
final favorites = FavoriteController(repository);
await favorites.load();
final logic = _logic(
_favoriteDrama,
FakeWatchHistory(),
favorites: favorites,
);
expect(logic.adjustedFavoriteCount, 2);
expect(await logic.toggleFavorite(), isTrue);
expect(logic.adjustedFavoriteCount, 3);
repository.failToggle = true;
expect(await logic.toggleFavorite(), isFalse);
expect(logic.adjustedFavoriteCount, 3);
repository.failToggle = false;
expect(await logic.toggleFavorite(), isTrue);
expect(logic.adjustedFavoriteCount, 2);
logic.dispose();
});
test('should_decrement_favorite_count_from_saved_state', () async {
final repository = InMemoryFavoriteRepository(
saved: {'favorite-detail'},
cards: [_favoriteDrama],
);
final favorites = FavoriteController(repository);
await favorites.load();
final logic = _logic(
_favoriteDrama,
FakeWatchHistory(),
favorites: favorites,
);
expect(await logic.toggleFavorite(), isTrue);
expect(logic.adjustedFavoriteCount, 1);
logic.dispose();
});
}
const _favoriteDrama = Drama(
id: 'favorite-detail',
title: 'Favorite detail',
synopsis: 'favorite count',
posterUrl: '/files/favorite-detail.jpg',
favoriteCount: 2,
detailLoaded: true,
);