import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:qlyra/backend/modules/messages.dart'; import 'package:qlyra/frontend/widgets/attachment/bubbles/video_note_bubble.dart'; import 'package:qlyra/frontend/widgets/message_bubble.dart'; import 'package:qlyra/l10n/app_localizations.dart'; import 'package:qlyra/models/attachment.dart'; const int _me = 1; const int _peer = 7; const int _longNoteMs = 45000; CachedMessage _note({required int durationMs}) => CachedMessage( id: '1', accountId: _me, chatId: 2, senderId: _peer, time: DateTime(2026, 1, 1, 5, 46).millisecondsSinceEpoch, status: 'sent', attachments: [ VideoAttachment( videoId: 4242, videoToken: 'synthetic-token', videoType: 1, width: 400, height: 400, duration: durationMs, ), ], ); Future _pumpNote( WidgetTester tester, { required double screenWidth, }) async { tester.view.physicalSize = Size(screenWidth * 2, 2400); tester.view.devicePixelRatio = 2; addTearDown(tester.view.reset); await tester.pumpWidget( MaterialApp( locale: const Locale('ru'), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: Align( alignment: Alignment.topLeft, child: MessageBubble( message: _note(durationMs: _longNoteMs), isMe: false, myId: _me, chatType: 'DIALOG', ), ), ), ), ); await tester.pump(); } void main() { testWidgets('у кружка есть длительность слева на одном Y с временем', ( tester, ) async { await _pumpNote(tester, screenWidth: 390); final duration = find.text('0:45'); final clock = find.text('05:46'); expect(duration, findsOneWidget); expect(clock, findsOneWidget); final durationBox = tester.getRect(duration); final clockBox = tester.getRect(clock); expect( durationBox.center.dy, closeTo(clockBox.center.dy, 1.0), reason: 'длительность и время должны быть на одном Y', ); expect( durationBox.right, lessThan(clockBox.left), reason: 'длительность должна быть слева от времени', ); final circle = tester.getRect(find.byType(VideoNoteBubble)); expect(durationBox.left, closeTo(circle.left, 8.0)); expect(clockBox.right, closeTo(circle.right, 12.0)); }); testWidgets('свёрнутый кружок сохраняет базовый размер', (tester) async { await _pumpNote(tester, screenWidth: 390); final size = tester.getSize(find.byType(VideoNoteBubble)); expect(size.width, closeTo(210, 0.5)); }); testWidgets('кружку хватает ширины под увеличение', (tester) async { const expanded = 210 * 1.7; final reached = {}; for (final screenWidth in [360.0, 390.0, 412.0, 800.0]) { await _pumpNote(tester, screenWidth: screenWidth); expect( tester.takeException(), isNull, reason: 'переполнение раскладки при ширине $screenWidth', ); final box = tester.renderObject(find.byType(VideoNoteBubble)) as RenderBox; final available = box.constraints.maxWidth; reached[screenWidth] = (available / 210).clamp(1.0, 1.7); expect( available, lessThanOrEqualTo(screenWidth), reason: 'кружку дали больше ширины, чем есть на экране', ); } expect(reached[390.0], closeTo(1.7, 0.001)); expect(reached[412.0], closeTo(1.7, 0.001)); expect(reached[800.0], closeTo(1.7, 0.001)); expect(reached[360.0], closeTo((360 - 24) / 210, 0.001)); expect(reached[360.0], greaterThan(1.55)); expect(expanded, 357); }); }