7dceefc55e
- 默认模板改为代码只读基准:readLabelTemplates 加载时强制用 builtinDefault() 覆盖 builtin-default 项,忽略存储里的旧脏几何 (旧默认品名被关/旧 QR 坐标等一律自愈回代码基准) - 二维码放大 x198/y44/尺寸96 → x192/y32/尺寸120,四周留 ~1mm 小边框 - 原型 label-template-editor.html 高级 QR 输入同步;golden 重生 - 新增存储测试钉死「内置默认永远回代码基准」 原型与代码同提交(design-first 双边一致)
116 lines
4.3 KiB
Dart
116 lines
4.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jiu_client/core/utils/label_template.dart';
|
|
|
|
/// 锁死模板存储读写(走 shop.custom_fields,零后端改动)与 JSON 往返,
|
|
/// 不触真实库——纯内存对象校验。
|
|
void main() {
|
|
group('LabelTemplate 存储 helpers', () {
|
|
test('custom_fields 无模板时回退内置默认', () {
|
|
final list = readLabelTemplates(<String, dynamic>{});
|
|
expect(list, hasLength(1));
|
|
expect(list.first.id, 'builtin-default');
|
|
});
|
|
|
|
test('activeLabelTemplate 按 id 命中,缺失回退第一项', () {
|
|
final a = LabelTemplate.builtinDefault();
|
|
final b = a.copyWith(id: 'tpl-2', name: '大字号');
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [a.toJson(), b.toJson()],
|
|
'label_template_active': 'tpl-2',
|
|
};
|
|
expect(activeLabelTemplate(cf).id, 'tpl-2');
|
|
|
|
cf['label_template_active'] = 'nope';
|
|
expect(activeLabelTemplate(cf).id, 'builtin-default');
|
|
});
|
|
|
|
test('toJson → fromJson 往返保真(几何/开关/样式)', () {
|
|
final src = LabelTemplate.builtinDefault();
|
|
src.textStack.subLines[0].fontSize = 16;
|
|
src.textStack.subLines[0].bold = true;
|
|
src.qr.size = 120;
|
|
src.print.direction = 0;
|
|
final back = LabelTemplate.fromJson(src.toJson());
|
|
expect(back.textStack.subLines[0].fontSize, 16);
|
|
expect(back.textStack.subLines[0].bold, true);
|
|
expect(back.qr.size, 120);
|
|
expect(back.print.direction, 0);
|
|
});
|
|
|
|
test('存 → 读回列表保持顺序与命名', () {
|
|
final a = LabelTemplate.builtinDefault();
|
|
final b = a.copyWith(id: 'tpl-2', name: '双语抬头');
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [a.toJson(), b.toJson()],
|
|
};
|
|
final list = readLabelTemplates(cf);
|
|
expect(list.map((t) => t.id), ['builtin-default', 'tpl-2']);
|
|
expect(list[1].name, '双语抬头');
|
|
});
|
|
|
|
test('老店铺旧默认 QR 加载时自动升级为居中坐标', () {
|
|
final def = LabelTemplate.builtinDefault();
|
|
// 构造两个历史默认签名的模板(贴头顶版 + 中间偏上版)
|
|
final legacyA = def.copyWith(id: 'tpl-legacy-a', name: '旧模板A');
|
|
legacyA.qr
|
|
..x = 178
|
|
..y = 25
|
|
..size = 134;
|
|
final legacyB = def.copyWith(id: 'tpl-legacy-b', name: '旧模板B');
|
|
legacyB.qr
|
|
..x = 190
|
|
..y = 34
|
|
..size = 116;
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [legacyA.toJson(), legacyB.toJson()],
|
|
};
|
|
final list = readLabelTemplates(cf);
|
|
for (final t in list) {
|
|
expect(t.qr.x, def.qr.x, reason: '${t.name} QR.x 应升级到新默认');
|
|
expect(t.qr.y, def.qr.y, reason: '${t.name} QR.y 应升级到新默认');
|
|
expect(t.qr.size, def.qr.size, reason: '${t.name} QR.size 应升级到新默认');
|
|
}
|
|
});
|
|
|
|
test('内置默认模板永远回代码基准:存储里被改脏也覆盖回 builtinDefault', () {
|
|
final def = LabelTemplate.builtinDefault();
|
|
// 模拟老库存的 builtin-default:品名被关、QR 乱改、字号乱改
|
|
final stale = def.copyWith();
|
|
stale.textStack.name.show = false;
|
|
stale.qr
|
|
..x = 10
|
|
..y = 10
|
|
..size = 200;
|
|
stale.textStack.subLines[0].fontSize = 99;
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [stale.toJson()],
|
|
};
|
|
final t =
|
|
readLabelTemplates(cf).firstWhere((x) => x.id == 'builtin-default');
|
|
expect(t.textStack.name.show, isTrue, reason: '品名默认必须展示');
|
|
expect(t.qr.x, def.qr.x);
|
|
expect(t.qr.y, def.qr.y);
|
|
expect(t.qr.size, def.qr.size);
|
|
expect(t.textStack.subLines[0].fontSize, def.textStack.subLines[0].fontSize);
|
|
});
|
|
|
|
test('用户自定义过的 QR 不匹配旧签名,加载时保持不动', () {
|
|
final custom = LabelTemplate.builtinDefault().copyWith(
|
|
id: 'tpl-custom',
|
|
name: '自定义位置',
|
|
);
|
|
custom.qr
|
|
..x = 210
|
|
..y = 60
|
|
..size = 80; // 与任一历史默认都不同
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [custom.toJson()],
|
|
};
|
|
final t = readLabelTemplates(cf).first;
|
|
expect(t.qr.x, 210);
|
|
expect(t.qr.y, 60);
|
|
expect(t.qr.size, 80);
|
|
});
|
|
});
|
|
}
|