Files
jiu/client/test/label_template_storage_test.dart
T
wangjia 7dceefc55e feat(client): 价签默认模板品名默认展示 + 二维码放大留小边框
- 默认模板改为代码只读基准:readLabelTemplates 加载时强制用
  builtinDefault() 覆盖 builtin-default 项,忽略存储里的旧脏几何
  (旧默认品名被关/旧 QR 坐标等一律自愈回代码基准)
- 二维码放大 x198/y44/尺寸96 → x192/y32/尺寸120,四周留 ~1mm 小边框
- 原型 label-template-editor.html 高级 QR 输入同步;golden 重生
- 新增存储测试钉死「内置默认永远回代码基准」

原型与代码同提交(design-first 双边一致)
2026-08-31 12:07:22 +08:00

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);
});
});
}