Files
IKAR/test/message_status_icon_test.dart

233 lines
7.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:ikar/backend/modules/messages.dart';
import 'package:ikar/core/config/app_message_status_size.dart';
import 'package:ikar/frontend/widgets/message_bubble.dart';
import 'package:ikar/frontend/widgets/message_status_icon.dart';
import 'package:ikar/frontend/widgets/text_with_meta.dart';
import 'package:ikar/l10n/app_localizations.dart';
void main() {
setUp(() => AppMessageStatusSize.current.value = 1);
tearDown(() => AppMessageStatusSize.current.value = 1);
testWidgets('receipt icons retain their base size and resize live', (
tester,
) async {
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: Row(
children: [
MessageStatusIcon(icon: Symbols.check, size: 12),
MessageStatusIcon(icon: Symbols.done, size: 13),
MessageStatusIcon(icon: Symbols.done_all, size: 14),
],
),
),
),
);
void expectSizes(double scale) {
for (final (icon, baseSize) in [
(Symbols.check, 12.0),
(Symbols.done, 13.0),
(Symbols.done_all, 14.0),
]) {
final finder = find.byIcon(icon);
expect(tester.widget<Icon>(finder).size, baseSize * scale);
expect(tester.getSize(finder), Size.square(baseSize * scale));
}
}
expectSizes(1);
AppMessageStatusSize.current.value = 1.237;
await tester.pump();
expectSizes(1.237);
AppMessageStatusSize.current.value = 1.5;
await tester.pump();
expectSizes(1.5);
expect(tester.takeException(), isNull);
});
testWidgets('error and pending icons keep their size', (tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: Row(
children: [
MessageStatusIcon(icon: Symbols.error, size: 14),
MessageStatusIcon(icon: Symbols.schedule, size: 14),
Icon(Symbols.check, size: 14),
],
),
),
),
);
AppMessageStatusSize.current.value = 1.5;
await tester.pump();
for (final icon in [Symbols.error, Symbols.schedule, Symbols.check]) {
final finder = find.byIcon(icon);
expect(tester.widget<Icon>(finder).size, 14);
expect(tester.getSize(finder), const Size.square(14));
}
});
for (final text in ['Hi', 'A longer message that fills several lines']) {
testWidgets('enlarged receipts remain inside text metadata: $text', (
tester,
) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Align(
alignment: Alignment.topLeft,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 140),
child: TextWithMeta(
key: const ValueKey('text-with-meta'),
text: Text(text, style: const TextStyle(fontSize: 16)),
meta: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('12:34', style: TextStyle(fontSize: 10)),
SizedBox(width: 4),
MessageStatusIcon(icon: Symbols.done_all, size: 14),
],
),
),
),
),
),
),
);
AppMessageStatusSize.current.value = 1.5;
await tester.pump();
final parent = tester.getRect(
find.byKey(const ValueKey('text-with-meta')),
);
final icon = tester.getRect(find.byIcon(Symbols.done_all));
expect(icon.size, const Size.square(21));
expect(icon.left, greaterThanOrEqualTo(parent.left));
expect(icon.top, greaterThanOrEqualTo(parent.top));
expect(icon.right, lessThanOrEqualTo(parent.right));
expect(icon.bottom, lessThanOrEqualTo(parent.bottom));
expect(tester.takeException(), isNull);
});
}
testWidgets('padded receipts fit the final line of a multiline caption', (
tester,
) async {
const caption = 'First line\nHi';
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Align(
alignment: Alignment.topLeft,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 200),
child: TextWithMeta(
key: const ValueKey('caption-with-meta'),
fillWidth: true,
text: const Text(
caption,
style: TextStyle(fontSize: 16, height: 1.3),
),
meta: const Padding(
key: ValueKey('caption-meta'),
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('12:34', style: TextStyle(fontSize: 10)),
SizedBox(width: 4),
MessageStatusIcon(icon: Symbols.done_all, size: 14),
],
),
),
),
),
),
),
),
);
AppMessageStatusSize.current.value = 1.5;
await tester.pump();
final paragraph = tester.renderObject<RenderParagraph>(find.text(caption));
final caret = paragraph.getOffsetForCaret(
TextPosition(offset: caption.length),
Rect.zero,
);
final finalLineTop = paragraph.localToGlobal(caret).dy;
final text = tester.getRect(find.text(caption));
final parent = tester.getRect(
find.byKey(const ValueKey('caption-with-meta')),
);
final meta = tester.getRect(find.byKey(const ValueKey('caption-meta')));
expect(caret.dy, greaterThan(0));
expect(caret.dx + 8 + meta.width, lessThanOrEqualTo(parent.width));
expect(meta.height, 25);
expect(meta.top, greaterThanOrEqualTo(finalLineTop - 0.01));
expect(meta.top, lessThan(text.bottom));
expect(meta.bottom, lessThanOrEqualTo(parent.bottom));
expect(
tester.getSize(find.byIcon(Symbols.done_all)),
const Size.square(21),
);
expect(tester.takeException(), isNull);
});
testWidgets('an existing own message receives scale and read updates', (
tester,
) async {
final readTime = ValueNotifier<int>(0);
addTearDown(readTime.dispose);
final message = CachedMessage(
id: 'status-scale-test',
accountId: 1,
chatId: 2,
senderId: 1,
text: 'Hi',
time: 1000,
status: 'sent',
);
await tester.pumpWidget(
MaterialApp(
locale: const Locale('ru'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(
body: Align(
alignment: Alignment.topRight,
child: MessageBubble(
message: message,
isMe: true,
myId: 1,
chatType: 'DIALOG',
otherReadTime: readTime,
),
),
),
),
);
expect(tester.widget<Icon>(find.byIcon(Symbols.check)).size, 14);
AppMessageStatusSize.current.value = 1.5;
await tester.pump();
expect(tester.widget<Icon>(find.byIcon(Symbols.check)).size, 21);
readTime.value = message.time;
await tester.pump();
expect(find.byIcon(Symbols.check), findsNothing);
expect(tester.widget<Icon>(find.byIcon(Symbols.done_all)).size, 21);
expect(tester.takeException(), isNull);
});
}