/// 分享二维码对话框 widget 测试(UI-01 §4.5 分层重构)。 /// /// 覆盖:分层结构(相册标题 → 白底二维码 → URL 文本 → 复制为主/浏览器 /// 打开为次)、QrImageView 以 viewer URL({VIEWER_BASE}/a/{token})渲染、 /// 复制按钮写入剪贴板并提示、「在浏览器中打开」经注入的替身启动器 /// 打开 URL 并关闭对话框。 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/core/config.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'; void main() { const token = 'sharetoken000000000001'; Future pumpDialog( WidgetTester tester, { String? albumTitle, UrlLauncher? launcher, }) async { await tester.pumpWidget( ProviderScope( overrides: [ if (launcher != null) urlLauncherProvider.overrideWith((ref) => launcher), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, // 复制提示走 ScaffoldMessenger:包一层 Scaffold 供 SnackBar 挂载。 home: Scaffold( body: Center( child: ShareQrDialog( publicToken: token, albumTitle: albumTitle, ), ), ), ), ), ); await tester.pumpAndSettle(); } testWidgets('分层渲染:相册标题 → 二维码(data 为观众链接)→ URL 文本', (tester) async { await pumpDialog(tester, albumTitle: 'Opening Gala'); final url = ApiConfig.viewerAlbumUrl(token); // qr_flutter 4.1 未公开 QrImageView.data(私有 _data),以同源的 // SelectableText 文本断言 URL 构造(二维码与文本同用该局部变量)。 expect(find.byType(QrImageView), findsOneWidget); expect( tester.widget(find.byType(SelectableText)).data, url, ); expect(url, 'http://10.0.2.2:5175/a/$token'); // 分层:主标题 = 相册名,副标题 = 通用标题,脚注 = 扫码/链接提示。 expect(find.text('Opening Gala'), findsOneWidget); expect(find.text('Share QR code'), findsOneWidget); expect(find.text('Scan the code or open the link to view'), findsOneWidget); }); testWidgets('复制按钮(主操作)→ 剪贴板收到 URL + 已复制提示', (tester) async { final clipboardCalls = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( SystemChannels.platform, (call) async { clipboardCalls.add(call); return null; }, ); await pumpDialog(tester); await tester.tap(find.text('Copy link')); await tester.pumpAndSettle(); final url = ApiConfig.viewerAlbumUrl(token); expect( clipboardCalls.any( (c) => c.method == 'Clipboard.setData' && (c.arguments as Map)['text'] == url, ), isTrue, ); expect(find.text('Copied'), findsOneWidget); }); testWidgets('在浏览器中打开(次操作)→ 启动器收到 URL + 关闭对话框', (tester) async { final launchedUrls = []; await pumpDialog( tester, launcher: (url) async { launchedUrls.add(url); return true; }, ); await tester.tap(find.text('Open in browser')); await tester.pumpAndSettle(); expect(launchedUrls, [ApiConfig.viewerAlbumUrl(token)]); expect(find.byType(ShareQrDialog), findsNothing, reason: '打开成功后关闭'); }); }