Files
Qlyra/test/lottie_slash_icon_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

139 lines
4.6 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:qlyra/frontend/widgets/lottie_slash_icon.dart';
import 'package:lottie/lottie.dart';
const _asset = 'assets/lottie/ic_flash_on_to_off.json';
Map<String, dynamic> _doc() =>
jsonDecode(File(_asset).readAsStringSync()) as Map<String, dynamic>;
List<Map<String, dynamic>> _layers(Map<String, dynamic> doc) =>
(doc['layers'] as List).cast<Map<String, dynamic>>();
List<Map<String, dynamic>> _maskFrames(Map<String, dynamic> layer) {
final masks = (layer['masksProperties'] as List).cast<Map<String, dynamic>>();
return ((masks.single['pt'] as Map)['k'] as List)
.cast<Map<String, dynamic>>();
}
List<List<num>> _quad(Map<String, dynamic> frame) =>
((((frame['s'] as List).first as Map)['v']) as List)
.map((point) => (point as List).cast<num>())
.toList();
Widget _host(bool slashed) => MaterialApp(
home: Scaffold(
body: Center(
child: LottieSlashIcon(
asset: _asset,
slashed: slashed,
color: const Color(0xFFFFFFFF),
),
),
),
);
void main() {
group('Ассет перечёркивания', () {
test('квадратный, из двух слоёв, каждый со своей маской', () {
final doc = _doc();
expect(doc['w'], doc['h']);
expect(doc['op'], greaterThan(0));
final layers = _layers(doc);
expect(layers.length, 2);
for (final layer in layers) {
expect(_maskFrames(layer).length, 2, reason: 'маска должна ехать');
final group = (layer['shapes'] as List).first as Map<String, dynamic>;
final paths = (group['it'] as List).cast<Map<String, dynamic>>().where(
(item) => item['ty'] == 'sh',
);
expect(paths, isNotEmpty);
for (final path in paths) {
expect(
(path['ks'] as Map)['a'],
0,
reason: 'глифы статичны — двигается только маска',
);
}
}
});
test('маски слоёв дополняют друг друга', () {
final layers = _layers(_doc());
final slashed = _maskFrames(layers.first);
final plain = _maskFrames(layers.last);
for (var frame = 0; frame < 2; frame++) {
final a = _quad(slashed[frame]);
final b = _quad(plain[frame]);
expect(
a.take(2),
b.take(2),
reason: 'обе маски должны делить одну и ту же диагональ',
);
expect(
a.skip(2),
isNot(b.skip(2)),
reason: 'маски должны смотреть в разные стороны от диагонали',
);
}
});
test('слои двигаются одинаково', () {
final layers = _layers(_doc());
expect(layers.first['ks'], layers.last['ks']);
});
testWidgets('композиция читается lottie без предупреждений', (
tester,
) async {
final composition = await AssetLottie(_asset).load();
expect(composition.warnings, isEmpty);
expect(composition.layers.length, 2);
});
});
group('LottieSlashIcon', () {
testWidgets('рисует lottie в обоих состояниях', (tester) async {
await tester.pumpWidget(_host(false));
await tester.pump();
expect(find.byType(Lottie), findsOneWidget);
await tester.pumpWidget(_host(true));
await tester.pump(const Duration(milliseconds: 100));
expect(find.byType(Lottie), findsOneWidget);
await tester.pump(const Duration(milliseconds: 400));
expect(find.byType(Lottie), findsOneWidget);
});
testWidgets('перечёркивание анимируется в обе стороны', (tester) async {
await tester.pumpWidget(_host(false));
final controller = tester
.widget<LottieBuilder>(find.byType(LottieBuilder))
.controller!;
expect(controller.value, 0);
await tester.pumpWidget(_host(true));
await tester.pump(const Duration(milliseconds: 100));
expect(controller.value, greaterThan(0));
expect(controller.value, lessThan(1));
await tester.pump(const Duration(milliseconds: 400));
expect(controller.value, 1);
await tester.pumpWidget(_host(false));
await tester.pump(const Duration(milliseconds: 100));
expect(controller.value, lessThan(1));
await tester.pump(const Duration(milliseconds: 400));
expect(controller.value, 0);
});
});
}