/// 相册分享页 widget 测试(UI-03 §4 页面 19)。 /// /// 覆盖:全屏页结构(标题/真实封面占位/名称/日期地点/二维码/扫码说明/ /// 可选中链接)、链接携带正确相册 token 与 `?lang=` 语言参数、Copy link /// 主操作写剪贴板 + 已复制提示、Open in browser 次操作经注入替身启动器 /// 打开并退出页面、未公开相册显示「该链接目前无法公开浏览」琥珀提示 /// (公开相册不显示)。 library; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:photo_live/features/albums/models.dart'; import 'package:photo_live/l10n/app_localizations.dart'; import 'package:photo_live/pages/share_qr_dialog.dart'; import 'package:qr_flutter/qr_flutter.dart'; import '../helpers/fakes.dart'; void main() { const token = 'sharetoken000000000001'; Future pumpPage( WidgetTester tester, { bool publicEnabled = true, UrlLauncher? launcher, }) async { await tester.pumpWidget( ProviderScope( overrides: [ if (launcher != null) urlLauncherProvider.overrideWith((ref) => launcher), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: ShareQrPage( album: Album.fromJson( albumJson(publicToken: token, publicEnabled: publicEnabled), ), ), ), ), ); await tester.pumpAndSettle(); } testWidgets('全屏页结构:标题/封面/名称/日期地点/二维码/扫码说明/链接', ( tester, ) async { await pumpPage(tester); // 全屏页 AppBar 标题(不再是 Dialog)。 expect(find.byType(AppBar), findsOneWidget); expect(find.text('Share album'), findsOneWidget); // 真实封面位(无封面 → 同尺寸中性占位,不破图不空行)。 expect(find.byIcon(Icons.image_outlined), findsOneWidget); // 名称与日期地点(en 回退:Opening Gala;上海墙钟 14:30)。 expect(find.text('Opening Gala'), findsOneWidget); expect( find.text('2026/9/18 14:30 · 大宴会厅'), findsOneWidget, reason: '开始时间(相册时区;结束未定不伪造区间)+ 场地(展示回退链)', ); // UI06 三方式:系统分享(默认)/ 生成二维码海报 / 复制链接。 expect(find.text('Share to...'), findsOneWidget); expect(find.text('Generate QR poster'), findsOneWidget); expect(find.text('Copy link'), findsOneWidget); // 可选中链接(二维码与复制共用同一 URL)。 final url = 'http://10.0.2.2:5175/a/$token?lang=en'; expect( tester.widget(find.byType(SelectableText)).data, url, reason: '链接文本(?lang= 随 App 语言)', ); // 点「生成二维码海报」→ 弹层:标题/时间/地址/二维码/下载按钮。 await tester.tap(find.text('Generate QR poster')); await tester.pumpAndSettle(); expect(find.byType(QrImageView), findsOneWidget); expect(find.text('Scan to view photos'), findsOneWidget); expect(find.text('Download poster image'), findsOneWidget); // UI06:海报日期粒度(无时间)。 expect(find.text('2026/9/18'), findsOneWidget); }); testWidgets('Copy link(主操作)→ 剪贴板收到带 lang 的 URL + 已复制提示', (tester) async { final clipboardCalls = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( SystemChannels.platform, (call) async { clipboardCalls.add(call); return null; }, ); await pumpPage(tester); await tester.ensureVisible(find.text('Copy link')); await tester.pumpAndSettle(); await tester.tap(find.text('Copy link')); await tester.pumpAndSettle(); expect( clipboardCalls.any( (c) => c.method == 'Clipboard.setData' && (c.arguments as Map)['text'] == 'http://10.0.2.2:5175/a/$token?lang=en', ), isTrue, ); expect(find.text('Copied'), findsOneWidget); }); testWidgets('Open in browser(次操作)→ 启动器收到 URL + 退出分享页', (tester) async { final launchedUrls = []; await pumpPage( tester, launcher: (url) async { launchedUrls.add(url); return true; }, ); await tester.ensureVisible(find.text('Open in browser')); await tester.pumpAndSettle(); await tester.tap(find.text('Open in browser')); await tester.pumpAndSettle(); expect(launchedUrls, ['http://10.0.2.2:5175/a/$token?lang=en']); expect(find.byType(ShareQrPage), findsNothing, reason: '打开成功后退出'); }); testWidgets('未公开相册:琥珀提示链接不可公开浏览;公开相册不提示', (tester) async { await pumpPage(tester, publicEnabled: false); expect( find.text('This link is not publicly accessible yet'), findsOneWidget, ); await pumpPage(tester, publicEnabled: true); expect( find.text('This link is not publicly accessible yet'), findsNothing, reason: '公开相册不得显示不可浏览提示', ); }); }