206 lines
7.2 KiB
Dart
206 lines
7.2 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:ikar/backend/modules/messages.dart';
|
||
import 'package:ikar/core/config/app_message_actions_style.dart';
|
||
import 'package:ikar/frontend/screens/chats/chat/view/message_row_widgets.dart';
|
||
import 'package:ikar/frontend/widgets/attachment/bubbles/voice_bubble.dart';
|
||
import 'package:ikar/frontend/widgets/message_actions_overlay.dart';
|
||
import 'package:ikar/frontend/widgets/message_bubble.dart';
|
||
import 'package:ikar/l10n/app_localizations.dart';
|
||
import 'package:ikar/models/attachment.dart';
|
||
import 'package:ikar/main.dart' show api;
|
||
import 'package:material_symbols_icons/symbols.dart';
|
||
|
||
const _label = 'Расшифровка голосового сообщения';
|
||
|
||
CachedMessage _message({bool voice = true, String status = 'sent'}) =>
|
||
CachedMessage(
|
||
id: '901',
|
||
accountId: 1,
|
||
chatId: 10,
|
||
senderId: 7,
|
||
time: DateTime(2026, 1, 1, 10).millisecondsSinceEpoch,
|
||
status: status,
|
||
text: voice ? null : 'Обычное сообщение',
|
||
attachments: voice
|
||
? const [AudioAttachment(audioId: 942, duration: 5000)]
|
||
: null,
|
||
);
|
||
|
||
Future<void> _pumpRow(
|
||
WidgetTester tester,
|
||
CachedMessage message, {
|
||
double scale = 1,
|
||
}) async {
|
||
final selected = ValueNotifier(<String>{});
|
||
addTearDown(selected.dispose);
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
locale: const Locale('ru'),
|
||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||
supportedLocales: AppLocalizations.supportedLocales,
|
||
home: MediaQuery(
|
||
data: MediaQueryData(
|
||
size: const Size(800, 600),
|
||
textScaler: TextScaler.linear(scale),
|
||
),
|
||
child: Scaffold(
|
||
body: Padding(
|
||
padding: const EdgeInsets.all(24),
|
||
child: Align(
|
||
alignment: Alignment.topLeft,
|
||
child: SelectableMessageRow(
|
||
message: message,
|
||
isMe: false,
|
||
selectedIds: selected,
|
||
selectionAnim: const AlwaysStoppedAnimation(0),
|
||
isSelectionActive: () => false,
|
||
onToggleSelection: () {},
|
||
onEnterSelection: () {},
|
||
onStartTextSelection: (_) {},
|
||
onDragTextSelection: (_) {},
|
||
onDelete: () {},
|
||
isPinned: () => false,
|
||
child: MessageBubble(
|
||
message: message,
|
||
isMe: false,
|
||
myId: 1,
|
||
chatType: 'DIALOG',
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
await tester.pump();
|
||
}
|
||
|
||
Future<void> _tapBubble(WidgetTester tester, {bool voice = true}) async {
|
||
if (voice) {
|
||
final rect = tester.getRect(find.byType(VoiceMessageBubble));
|
||
await tester.tapAt(Offset(rect.right - 12, rect.bottom - 6));
|
||
} else {
|
||
await tester.tap(find.text('Обычное сообщение'));
|
||
}
|
||
await tester.pump(const Duration(milliseconds: 220));
|
||
await tester.pumpAndSettle();
|
||
}
|
||
|
||
void main() {
|
||
// Initialize the shared API outside the widget test's fake timer zone.
|
||
tearDownAll(api.dispose);
|
||
setUp(TranscriptionCache.clear);
|
||
tearDown(TranscriptionCache.clear);
|
||
|
||
testWidgets(
|
||
'tap on the voice bubble opens a large transcription row and shows text',
|
||
(tester) async {
|
||
TranscriptionCache.put(
|
||
'901',
|
||
TranscriptionResult(status: 1, text: 'Проверка расшифровки'),
|
||
);
|
||
await _pumpRow(tester, _message());
|
||
expect(find.text('Т'), findsNothing);
|
||
expect(find.text('Проверка расшифровки'), findsNothing);
|
||
await _tapBubble(tester);
|
||
final action = find.ancestor(
|
||
of: find.text(_label),
|
||
matching: find.byType(InkWell),
|
||
);
|
||
expect(find.text(_label), findsOneWidget);
|
||
expect(tester.getSize(action).height, greaterThanOrEqualTo(48));
|
||
await tester.tap(find.text(_label));
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('Проверка расшифровки'), findsOneWidget);
|
||
await _tapBubble(tester);
|
||
await tester.tap(find.text('Скрыть расшифровку'));
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('Проверка расшифровки'), findsNothing);
|
||
await tester.pumpWidget(const SizedBox());
|
||
},
|
||
);
|
||
|
||
testWidgets('text and uploading voice messages do not offer transcription', (
|
||
tester,
|
||
) async {
|
||
await _pumpRow(tester, _message(voice: false));
|
||
await _tapBubble(tester, voice: false);
|
||
expect(find.text(_label), findsNothing);
|
||
await tester.tapAt(const Offset(780, 570));
|
||
await tester.pumpAndSettle();
|
||
await _pumpRow(tester, _message(status: 'sending'));
|
||
await _tapBubble(tester);
|
||
expect(find.text(_label), findsNothing);
|
||
await tester.pumpWidget(const SizedBox());
|
||
});
|
||
|
||
testWidgets(
|
||
'recognition progress and completion push update the voice bubble',
|
||
(tester) async {
|
||
await _pumpRow(tester, _message());
|
||
TranscriptionCache.put(
|
||
'901',
|
||
TranscriptionResult(status: 0),
|
||
expanded: true,
|
||
);
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('транскрибация...'), findsOneWidget);
|
||
TranscriptionCache.put(
|
||
'901',
|
||
TranscriptionResult(status: 1, text: 'Результат сервера'),
|
||
expanded: true,
|
||
);
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('Результат сервера'), findsOneWidget);
|
||
expect(find.text('транскрибация...'), findsNothing);
|
||
await tester.pumpWidget(const SizedBox());
|
||
},
|
||
);
|
||
|
||
testWidgets('the full menu label fits with larger text', (tester) async {
|
||
final controller = MessageActionsController();
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
locale: const Locale('ru'),
|
||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||
supportedLocales: AppLocalizations.supportedLocales,
|
||
builder: (context, child) => MediaQuery(
|
||
data: MediaQuery.of(
|
||
context,
|
||
).copyWith(textScaler: const TextScaler.linear(1.5)),
|
||
child: child!,
|
||
),
|
||
home: Scaffold(
|
||
body: Builder(
|
||
builder: (context) => TextButton(
|
||
onPressed: () => showMessageActions(
|
||
context: context,
|
||
originRect: const Rect.fromLTWH(24, 100, 240, 54),
|
||
tapPoint: const Offset(50, 120),
|
||
isMe: false,
|
||
messageText: null,
|
||
copyText: null,
|
||
controller: controller,
|
||
style: MessageActionsStyle.list,
|
||
interaction: MessageActionsInteraction.click,
|
||
onTranscribe: () {},
|
||
onDispose: controller.dispose,
|
||
),
|
||
child: const Text('open'),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
await tester.tap(find.text('open'));
|
||
await tester.pumpAndSettle();
|
||
expect(find.text(_label), findsOneWidget);
|
||
expect(find.byIcon(Symbols.speech_to_text), findsOneWidget);
|
||
expect(tester.takeException(), isNull);
|
||
await tester.tapAt(const Offset(780, 570));
|
||
await tester.pumpAndSettle();
|
||
});
|
||
}
|