import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:qlyra/frontend/screens/chats/chat/view/chat_preview_line.dart'; import 'package:qlyra/models/chat_preview_media.dart'; import 'package:material_symbols_icons/symbols.dart'; const String _pixel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ' 'AAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='; const TextStyle _style = TextStyle(fontSize: 14, height: 1.2); Widget _host(Widget child) => MaterialApp( home: Scaffold(body: Center(child: child)), ); String _plainText(WidgetTester tester) { final span = tester.widget(find.byType(Text).first).textSpan!; final buffer = StringBuffer(); span.visitChildren((child) { if (child is TextSpan && child.text != null) buffer.write(child.text); return true; }); return buffer.toString(); } List _spans(WidgetTester tester) { final span = tester.widget(find.byType(Text).first).textSpan!; final result = []; span.visitChildren((child) { if (child is TextSpan && child.text != null) result.add(child); return true; }); return result; } void main() { testWidgets('фото без подписи: миниатюра и курсивная подпись', ( tester, ) async { await tester.pumpWidget( _host( const ChatPreviewLine( text: 'Изображение', style: _style, media: ChatPreviewMedia( kind: ChatPreviewKind.photo, thumbs: [ChatPreviewThumb(source: _pixel)], label: 'Изображение', ), ), ), ); expect(find.byType(Image), findsOneWidget); expect(find.byIcon(Symbols.play_arrow), findsNothing); expect(_plainText(tester), 'Изображение'); expect(_spans(tester).single.style?.fontStyle, FontStyle.italic); }); testWidgets('фото с подписью: миниатюра и обычный текст', (tester) async { await tester.pumpWidget( _host( const ChatPreviewLine( prefix: 'Кто-то: ', text: 'смотри', style: _style, media: ChatPreviewMedia( kind: ChatPreviewKind.photo, thumbs: [ChatPreviewThumb(source: _pixel)], ), ), ), ); expect(find.byType(Image), findsOneWidget); expect(_plainText(tester), 'Кто-то: смотри'); expect(_spans(tester).last.style?.fontStyle, isNot(FontStyle.italic)); }); testWidgets('видео помечается иконкой проигрывания на миниатюре', ( tester, ) async { await tester.pumpWidget( _host( const ChatPreviewLine( text: 'Видео', style: _style, media: ChatPreviewMedia( kind: ChatPreviewKind.video, thumbs: [ ChatPreviewThumb(source: _pixel, video: true), ChatPreviewThumb(source: _pixel), ], label: 'Видео', ), ), ), ); expect(find.byType(Image), findsNWidgets(2)); expect(find.byIcon(Symbols.play_arrow), findsOneWidget); }); testWidgets('файл: иконка вместо слова и имя после двоеточия', ( tester, ) async { await tester.pumpWidget( _host( const ChatPreviewLine( text: 'Файл: notes.pdf', style: _style, media: ChatPreviewMedia( kind: ChatPreviewKind.file, label: 'Файл', detail: 'notes.pdf', ), ), ), ); expect(find.byIcon(Symbols.description), findsOneWidget); expect(_plainText(tester), ': notes.pdf'); }); testWidgets('специфичная подпись идёт с иконкой и курсивом', (tester) async { await tester.pumpWidget( _host( const ChatPreviewLine( text: 'Пропущенный звонок', style: _style, media: ChatPreviewMedia( kind: ChatPreviewKind.missedCall, label: 'Пропущенный звонок', ), ), ), ); expect(find.byIcon(Symbols.call_missed), findsOneWidget); expect(_plainText(tester), 'Пропущенный звонок'); expect(_spans(tester).single.style?.fontStyle, FontStyle.italic); }); testWidgets('метка пересылки остаётся перед иконкой', (tester) async { await tester.pumpWidget( _host( const ChatPreviewLine( text: '↪ Контакт', style: _style, media: ChatPreviewMedia( kind: ChatPreviewKind.contact, label: '↪ Контакт', ), ), ), ); expect(find.byIcon(Symbols.person), findsOneWidget); expect(_plainText(tester), '↪ Контакт'); }); testWidgets('ссылка с текстом сообщения не тащит иконку', (tester) async { await tester.pumpWidget( _host( const ChatPreviewLine( text: 'глянь qlyra.ru', style: _style, media: ChatPreviewMedia(kind: ChatPreviewKind.share), ), ), ); expect(find.byIcon(Symbols.link), findsNothing); expect(_plainText(tester), 'глянь qlyra.ru'); }); testWidgets('без описания вложения строка остаётся обычным текстом', ( tester, ) async { await tester.pumpWidget( _host(const ChatPreviewLine(text: 'привет', style: _style)), ); expect(find.byType(Image), findsNothing); expect(_plainText(tester), 'привет'); }); test('иконка типа чата зависит от вида чата', () { expect(chatKindIcon('CHANNEL', isBot: false), Symbols.campaign); expect(chatKindIcon('CHAT', isBot: false), Symbols.group); expect(chatKindIcon('GROUP', isBot: false), Symbols.group); expect(chatKindIcon('DIALOG', isBot: true), Symbols.smart_toy); expect(chatKindIcon('DIALOG', isBot: false), isNull); }); }