Files
nj/app/test/data/models/journal_element_test.dart
iven 4c743e150e test(app): 前端第一批测试 — EditorBloc 19用例 + JournalElement 11用例 + InMemoryRepo 12用例
添加 mocktail 测试依赖 + 字体文件占位
总计 42 测试通过,覆盖工具/笔画/元素/撤销/重做/序列化/乐观锁/CRUD
2026-06-01 23:02:14 +08:00

203 lines
6.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// JournalElement 模型单元测试
//
// 覆盖工厂方法、便利工厂、copyWith 不可变性、序列化往返、默认值
import 'dart:math';
import 'package:flutter_test/flutter_test.dart';
import 'package:nuanji_app/data/models/journal_element.dart';
void main() {
group('JournalElement', () {
// ===== create 工厂 =====
test('create 工厂生成正确的默认值', () {
final element = JournalElement.create(
journalId: 'journal-1',
elementType: ElementType.text,
positionX: 10,
positionY: 20,
content: {'text': 'Hello'},
);
expect(element.journalId, 'journal-1');
expect(element.elementType, ElementType.text);
expect(element.positionX, 10.0);
expect(element.positionY, 20.0);
expect(element.width, 100.0);
expect(element.height, 100.0);
expect(element.rotation, 0.0);
expect(element.zIndex, 0);
expect(element.version, 1);
expect(element.id, isNotEmpty);
expect(element.createdAt, isNotNull);
expect(element.updatedAt, isNotNull);
});
// ===== createText =====
test('createText 便利工厂', () {
final element = JournalElement.createText(
journalId: 'j-1',
text: '你好',
position: const Offset(50, 100),
fontSize: 24.0,
fontColor: '#E07A5F',
);
expect(element.elementType, ElementType.text);
expect(element.content['text'], '你好');
expect(element.content['fontSize'], 24.0);
expect(element.content['fontColor'], '#E07A5F');
expect(element.positionX, 50.0);
expect(element.positionY, 100.0);
});
test('createText 使用默认字号和颜色', () {
final element = JournalElement.createText(
journalId: 'j-1',
text: '默认',
position: Offset.zero,
);
expect(element.content['fontSize'], 18.0);
expect(element.content['fontColor'], '#2D2420');
});
// ===== createImage =====
test('createImage 便利工厂', () {
final element = JournalElement.createImage(
journalId: 'j-1',
filePath: '/path/to/image.jpg',
position: Offset.zero,
thumbnailPath: '/path/to/thumb.jpg',
);
expect(element.elementType, ElementType.image);
expect(element.content['filePath'], '/path/to/image.jpg');
expect(element.content['thumbnailPath'], '/path/to/thumb.jpg');
});
test('createImage 无 thumbnailPath 时不包含该字段', () {
final element = JournalElement.createImage(
journalId: 'j-1',
filePath: '/path/to/img.jpg',
position: Offset.zero,
);
expect(element.content.containsKey('thumbnailPath'), isFalse);
expect(element.content['filePath'], '/path/to/img.jpg');
});
// ===== createSticker =====
test('createSticker 便利工厂', () {
final element = JournalElement.createSticker(
journalId: 'j-1',
emoji: '🐱',
position: const Offset(50, 50),
stickerPackId: 'pack-1',
stickerId: 's-1',
);
expect(element.elementType, ElementType.sticker);
expect(element.content['emoji'], '🐱');
expect(element.content['stickerPackId'], 'pack-1');
expect(element.content['stickerId'], 's-1');
});
test('createSticker 无可选字段时不包含', () {
final element = JournalElement.createSticker(
journalId: 'j-1',
emoji: '🌸',
position: Offset.zero,
);
expect(element.content.containsKey('stickerPackId'), isFalse);
expect(element.content.containsKey('stickerId'), isFalse);
expect(element.content['emoji'], '🌸');
});
// ===== copyWith 不可变性 =====
test('copyWith 返回新实例且不修改原始', () {
final original = JournalElement.createText(
journalId: 'j-1',
text: '原始',
position: Offset.zero,
);
final modified = original.copyWith(
positionX: 100.0,
positionY: 200.0,
);
expect(identical(original, modified), isFalse);
expect(original.positionX, 0.0);
expect(original.positionY, 0.0);
expect(modified.positionX, 100.0);
expect(modified.positionY, 200.0);
expect(modified.journalId, original.journalId);
expect(modified.id, original.id);
});
// ===== 序列化 =====
test('toJson / fromJson 往返一致', () {
final original = JournalElement.createText(
journalId: 'j-1',
text: '序列化测试',
position: const Offset(42, 84),
fontSize: 20.0,
);
final json = original.toJson();
final restored = JournalElement.fromJson(json);
expect(restored.id, original.id);
expect(restored.journalId, original.journalId);
expect(restored.elementType, original.elementType);
expect(restored.positionX, original.positionX);
expect(restored.positionY, original.positionY);
expect(restored.content['text'], original.content['text']);
expect(restored.version, original.version);
});
test('fromJson 处理空 content', () {
final json = {
'id': 'test-id',
'journal_id': 'j-1',
'element_type': 'text',
'position_x': 0.0,
'position_y': 0.0,
'width': 100.0,
'height': 100.0,
'rotation': 0.0,
'z_index': 0,
'content': <String, dynamic>{},
'version': 1,
'created_at': DateTime.now().toIso8601String(),
'updated_at': DateTime.now().toIso8601String(),
};
final element = JournalElement.fromJson(json);
expect(element.content, isA<Map>());
expect(element.content, isEmpty);
});
// ===== ElementType 枚举 =====
test('ElementType 枚举值完整', () {
expect(ElementType.values.length, 5);
expect(ElementType.values, containsAll([
ElementType.text,
ElementType.image,
ElementType.sticker,
ElementType.handwritingRef,
ElementType.tape,
]));
});
});
}