// Author: fruit.com.cn import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/core/data/models/notice.dart'; import 'package:fruitshorts/core/data/remote/api_client.dart'; import 'package:fruitshorts/core/data/repositories/notice_repository.dart'; import 'package:fruitshorts/core/data/services/notices_controller.dart'; void main() { test('should_append_next_page_until_loaded_count_reaches_total', () async { final repository = ScriptedNoticeRepository([ NoticePage(total: 3, notices: [_notice('1'), _notice('2')]), NoticePage(total: 3, notices: [_notice('3')]), ]); final controller = NoticesController(repository); await controller.load(); expect(controller.notices.map((item) => item.id), ['1', '2']); expect(controller.hasMore, isTrue); await controller.loadMore(); expect(controller.notices.map((item) => item.id), ['1', '2', '3']); expect(controller.hasMore, isFalse); expect(repository.calls.map((call) => call.pageIndex), [1, 2]); }); test('should_show_empty_state_when_total_is_zero', () async { final controller = NoticesController( ScriptedNoticeRepository([const NoticePage(total: 0)]), ); await controller.load(); expect(controller.loading, isFalse); expect(controller.notices, isEmpty); expect(controller.hasMore, isFalse); expect(controller.error, isNull); }); test('should_preserve_backend_message_when_page_load_fails', () async { final repository = ScriptedNoticeRepository([]) ..error = const ApiException(500, '公告服务暂不可用'); final controller = NoticesController(repository); await controller.load(); expect(controller.error, '公告服务暂不可用'); expect(controller.notices, isEmpty); }); test('should_replace_list_when_refreshed', () async { final repository = ScriptedNoticeRepository([ NoticePage(total: 2, notices: [_notice('1'), _notice('2')]), NoticePage(total: 1, notices: [_notice('9')]), ]); final controller = NoticesController(repository); await controller.load(); await controller.refresh(); expect(controller.notices.map((item) => item.id), ['9']); expect(controller.hasMore, isFalse); }); } AppNotice _notice(String id) => AppNotice( id: id, title: 'Notice $id', content: 'Content $id', type: 'SYSTEM', publishAt: DateTime(2026, 10, 17, 12), ); class ScriptedNoticeRepository implements NoticeRepository { ScriptedNoticeRepository(this.pages); final List pages; final List calls = []; Object? error; @override Future page({required int pageIndex, int pageSize = 20}) async { calls.add(NoticePageCall(pageIndex: pageIndex, pageSize: pageSize)); if (error != null) throw error!; if (pages.isEmpty) return const NoticePage(total: 0); return pages.removeAt(0); } } class NoticePageCall { const NoticePageCall({required this.pageIndex, required this.pageSize}); final int pageIndex; final int pageSize; }