feat(mobile): album management pages with qr share
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/// 照片管理占位页 widget 测试(P3 计划 Task 4)。
|
||||
///
|
||||
/// 覆盖:Task 9 占位横幅、基础列表(可见性/处理状态标签、时区时间)、
|
||||
/// 游标加载更多。完整交互由 Task 9 替换。
|
||||
library;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:photo_live/core/api_client.dart';
|
||||
import 'package:photo_live/features/albums/models.dart';
|
||||
import 'package:photo_live/l10n/app_localizations.dart';
|
||||
import 'package:photo_live/pages/album_photos_page.dart';
|
||||
|
||||
import '../helpers/fakes.dart';
|
||||
|
||||
void main() {
|
||||
late FakeSessionStore store;
|
||||
|
||||
setUp(() {
|
||||
store = FakeSessionStore();
|
||||
});
|
||||
|
||||
ApiClient clientOf(FakeAdapter adapter) => ApiClient(
|
||||
sessionStore: store,
|
||||
dio: Dio(BaseOptions(baseUrl: 'http://test.local'))
|
||||
..httpClientAdapter = adapter,
|
||||
);
|
||||
|
||||
Future<void> pumpPhotos(WidgetTester tester, ApiClient client) async {
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [apiClientProvider.overrideWith((ref) => client)],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: AlbumPhotosPage(album: Album.fromJson(albumJson())),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('占位横幅 + 列表标签 + 游标加载第二页', (tester) async {
|
||||
final page1 = List<Map<String, dynamic>>.generate(
|
||||
20,
|
||||
(i) => adminPhotoJson(
|
||||
photoId: 'ph-${(i + 1).toString().padLeft(8, '0')}',
|
||||
visibility: i % 2 == 0 ? 'published' : 'unpublished',
|
||||
processingState: i % 2 == 0 ? 'ready' : 'processing',
|
||||
),
|
||||
);
|
||||
final page2 = <Map<String, dynamic>>[
|
||||
// 区分度高的 ID:第二页条目渲染后可按标题前缀断言。
|
||||
adminPhotoJson(photoId: 'page2item'),
|
||||
];
|
||||
final adapter = FakeAdapter((o) {
|
||||
if (o.path != '/v1/albums/alb-1/photos') {
|
||||
throw StateError('unexpected ${o.method} ${o.path}');
|
||||
}
|
||||
final cursor = o.uri.queryParameters['cursor'];
|
||||
if (cursor == null) {
|
||||
return (200, cursorPageBody(page1, nextCursor: 'pc1'));
|
||||
}
|
||||
if (cursor == 'pc1') return (200, cursorPageBody(page2));
|
||||
throw StateError('unexpected cursor $cursor');
|
||||
});
|
||||
|
||||
await pumpPhotos(tester, clientOf(adapter));
|
||||
|
||||
// Task 9 占位横幅。
|
||||
expect(
|
||||
find.textContaining('the full experience ships in Task 9'),
|
||||
findsOneWidget,
|
||||
);
|
||||
// 标签与条目(ListView 懒构建,只断言在渲染的可见条目)。
|
||||
expect(find.text('Published'), findsWidgets);
|
||||
expect(find.text('Unpublished'), findsWidgets);
|
||||
expect(find.text('Ready'), findsWidgets);
|
||||
expect(find.text('Processing'), findsWidgets);
|
||||
expect(find.text('2026/9/18 15:00'), findsWidgets, reason: '相册时区展示');
|
||||
|
||||
// 滚动加载第二页。
|
||||
await tester.drag(find.byType(ListView), const Offset(0, -4000));
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
adapter.requests.last.uri.queryParameters['cursor'],
|
||||
'pc1',
|
||||
);
|
||||
// 第二页条目渲染(标题展示 photoId 前 8 位)。
|
||||
expect(find.textContaining('page2ite'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user