fix(home): 修复频道快速切换卡 loading

This commit is contained in:
Zhou Weidong committed 2026-10-21 17:46:42 +08:00
1 parent c8392b2f2a
commit 3c4d65a9b2
5 files changed
+408 -110

No files matched your search

@@ -95,26 +95,109 @@ void main() {
controller.dispose();
});
test('should_ignore_stale_response_when_channels_switch_quickly', () async {
final anime = Completer<FeedPage>();
final live = Completer<FeedPage>();
test(
'should_cache_both_channels_when_responses_complete_out_of_order',
() async {
final anime = Completer<FeedPage>();
final live = Completer<FeedPage>();
final animeRefresh = Completer<FeedPage>();
final repository = _ScriptedFeedRepository()
..enqueue(() => anime.future)
..enqueue(() => live.future)
..enqueue(() => animeRefresh.future);
final controller = HomeFeedController(repository);
final animeLoad = controller.selectChannel(HomeFeedChannel.anime);
final liveLoad = controller.selectChannel(HomeFeedChannel.live);
live.complete(FeedPage(dramas: [_drama('live')]));
await liveLoad;
anime.complete(FeedPage(dramas: [_drama('anime')]));
await animeLoad;
expect(controller.channel, HomeFeedChannel.live);
expect(controller.dramas.single.id, 'live');
await controller.selectChannel(HomeFeedChannel.anime);
expect(controller.dramas.single.id, 'anime');
animeRefresh.complete(FeedPage(dramas: [_drama('anime-refresh')]));
await pumpEventQueue();
expect(controller.dramas.single.id, 'anime-refresh');
controller.dispose();
},
);
test('should_retry_automatically_when_returning_to_failed_channel', () async {
final repository = _ScriptedFeedRepository()
..enqueue(() => anime.future)
..enqueue(() => live.future);
..enqueue(() async => throw StateError('offline'))
..enqueue(() async => FeedPage(dramas: [_drama('live')]))
..enqueue(() async => FeedPage(dramas: [_drama('anime-retry')]));
final controller = HomeFeedController(repository);
final animeLoad = controller.selectChannel(HomeFeedChannel.anime);
final liveLoad = controller.selectChannel(HomeFeedChannel.live);
live.complete(FeedPage(dramas: [_drama('live')]));
await liveLoad;
anime.complete(FeedPage(dramas: [_drama('anime')]));
await animeLoad;
await controller.selectChannel(HomeFeedChannel.anime);
expect(controller.lastError, contains('offline'));
expect(controller.loadingFirstPage, isFalse);
expect(controller.channel, HomeFeedChannel.live);
expect(controller.dramas.single.id, 'live');
await controller.selectChannel(HomeFeedChannel.live);
await controller.selectChannel(HomeFeedChannel.anime);
expect(controller.dramas.single.id, 'anime-retry');
expect(repository.calls, hasLength(3));
controller.dispose();
});
test('should_not_report_first_page_loading_without_inflight_request', () {
final controller = HomeFeedController(_ScriptedFeedRepository());
expect(controller.loaded, isFalse);
expect(controller.loadingFirstPage, isFalse);
controller.dispose();
});
test('should_finish_loading_with_error_when_request_times_out', () async {
final pending = Completer<FeedPage>();
final repository = _ScriptedFeedRepository()..enqueue(() => pending.future);
final controller = HomeFeedController(
repository,
requestTimeout: const Duration(milliseconds: 10),
);
await controller.selectChannel(HomeFeedChannel.anime);
expect(controller.loadingFirstPage, isFalse);
expect(controller.loaded, isTrue);
expect(controller.lastError, isNotNull);
controller.dispose();
});
test(
'should_ignore_old_failure_when_same_channel_new_request_succeeds',
() async {
final oldRefresh = Completer<FeedPage>();
final repository = _ScriptedFeedRepository()
..enqueue(
() async => FeedPage(
dramas: [_drama('a')],
nextCursor: 'next',
hasMore: true,
),
)
..enqueue(() async => FeedPage(dramas: [_drama('live')]))
..enqueue(() => oldRefresh.future)
..enqueue(() async => FeedPage(dramas: [_drama('b')], hasMore: false));
final controller = HomeFeedController(repository);
await controller.selectChannel(HomeFeedChannel.anime);
await controller.selectChannel(HomeFeedChannel.live);
await controller.selectChannel(HomeFeedChannel.anime);
await controller.loadMore();
oldRefresh.completeError(StateError('old failure'));
await pumpEventQueue();
expect(controller.dramas.map((drama) => drama.id), ['a', 'b']);
expect(controller.lastError, isNull);
controller.dispose();
},
);
test('should_keep_old_data_when_refresh_fails', () async {
final repository = _ScriptedFeedRepository()
..enqueue(() async => FeedPage(dramas: [_drama('old')]))