Files
Qlyra/test/message_reaction_animoji_test.dart
sevenhill f74057ce9b
Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s
Rebrand application as Qlyra
2026-08-30 13:16:17 +03:00

140 lines
4.2 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:qlyra/backend/modules/messages.dart';
import 'package:qlyra/frontend/widgets/lottie_image.dart';
import 'package:qlyra/frontend/widgets/message_bubble.dart';
import 'package:qlyra/l10n/app_localizations.dart';
import 'package:qlyra/models/animoji.dart';
const _reaction = '🔥';
const _messageId = 'synthetic-message';
CachedMessage _message() => const CachedMessage(
id: _messageId,
accountId: 1,
chatId: 2,
senderId: 3,
text: 'Synthetic message',
time: 1000,
payload: {
'reactionInfo': {
'counters': [
{'reaction': _reaction, 'count': 1},
],
'yourReaction': _reaction,
'totalCount': 1,
},
},
);
Future<void> _pumpBubble(
WidgetTester tester, {
required Animoji animoji,
required ValueListenable<ReactionAnimationEvent?> animation,
}) async {
await tester.pumpWidget(
MaterialApp(
locale: const Locale('ru'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(
body: MessageBubble(
message: _message(),
isMe: false,
myId: 1,
chatType: 'DIALOG',
reactionAnimation: animation,
reactionAnimojiResolver: (emoji) =>
emoji == _reaction ? animoji : null,
),
),
),
);
await tester.pump();
}
void main() {
testWidgets('reaction animoji stays static until its reaction is applied', (
tester,
) async {
final animation = ValueNotifier<ReactionAnimationEvent?>(null);
addTearDown(animation.dispose);
const animoji = Animoji(
id: 1,
emoji: _reaction,
iconUrl: 'https://example.test/reaction.png',
lottieUrl: 'https://example.test/reaction-idle.json',
lottiePlayUrl: 'https://example.test/reaction-play.json',
);
await _pumpBubble(tester, animoji: animoji, animation: animation);
var glyph = tester.widget<LottieImage>(find.byType(LottieImage));
expect(glyph.url, animoji.iconUrl);
expect(glyph.lottieUrl, isNull);
animation.value = const ReactionAnimationEvent(
messageId: 'different-synthetic-message',
emoji: _reaction,
token: 1,
);
await tester.pump();
glyph = tester.widget<LottieImage>(find.byType(LottieImage));
expect(glyph.lottieUrl, isNull);
animation.value = const ReactionAnimationEvent(
messageId: _messageId,
emoji: _reaction,
token: 2,
);
await tester.pump();
final animatedGlyphs = tester
.widgetList<LottieImage>(find.byType(LottieImage))
.toList();
expect(animatedGlyphs, hasLength(2));
final body = animatedGlyphs.singleWhere(
(item) => item.lottieUrl == animoji.lottieUrl,
);
final effect = animatedGlyphs.singleWhere(
(item) => item.lottieUrl == animoji.lottiePlayUrl,
);
expect(body.size, 18);
expect(body.repeat, isFalse);
expect(effect.size, 36);
expect(effect.repeat, isFalse);
final effectFinder = find.byWidgetPredicate(
(widget) =>
widget is LottieImage && widget.lottieUrl == animoji.lottiePlayUrl,
);
expect(tester.getSize(effectFinder), const Size.square(36));
final players = tester
.widgetList<LottiePlayer>(find.byType(LottiePlayer))
.toList();
expect(players, hasLength(2));
expect(players.every((player) => player.animate && !player.repeat), isTrue);
});
testWidgets('reaction without an icon holds the first lottie frame', (
tester,
) async {
final animation = ValueNotifier<ReactionAnimationEvent?>(null);
addTearDown(animation.dispose);
const animoji = Animoji(
id: 2,
emoji: _reaction,
lottieUrl: 'https://example.test/reaction-idle.json',
);
await _pumpBubble(tester, animoji: animoji, animation: animation);
final glyph = tester.widget<LottieImage>(find.byType(LottieImage));
expect(glyph.lottieUrl, animoji.lottieUrl);
expect(glyph.animate, isFalse);
expect(glyph.repeat, isFalse);
final player = tester.widget<LottiePlayer>(find.byType(LottiePlayer));
expect(player.animate, isFalse);
expect(player.repeat, isFalse);
});
}