服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
265 lines
20 KiB
TypeScript
265 lines
20 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { existsSync, readFileSync } from 'node:fs';
|
|
import { ceraDate, ceraSchemas, ceraTabProducts, changeCeraProduct, newCeraValues, nextCeraID, readCeraShop } from '../src/gui/ceraShop';
|
|
import { getGUIProvider } from '../src/gui/registry';
|
|
|
|
const item = '3000109 1 1 0 0 15 0 0 `Life Token` 0 0 -1 `` -1';
|
|
const avatar = '3107733 515540507 4 0 0 120 0 0 0 0 -1 -1 -1 ``';
|
|
const pkg = '3400245 590713421 0 0 599 0 0 `Summer Box` 90 0 -1 -1 `20241105`';
|
|
function fixture(eol = '\n') {
|
|
return ['# 😀 注释保留', '[item]', item, '[/item]', '[dont trade avatar]', avatar, '[/dont trade avatar]', '[package]', pkg, '[/package]',
|
|
'[shop button list and sequence]', '`event` `mileage` `hotandnew` `package` `avatar` `item` `exit`', '[/shop button list and sequence]',
|
|
'[purchasing limit]', '3000109 1 0 2 0 0 0 0', '[/purchasing limit]', '[specific product mileage]', '3000109 5', '[/specific product mileage]',
|
|
'[hotnew sell ipg]', '3000109 6', '[/hotnew sell ipg]', '[storage]', '[cargo 1]', '3000109 1', '[cargo 1]', '3400245 590713421', '[/storage]',
|
|
'[visible storage]', '[cargo 1]', '1 3000109', '[/visible storage]', '[unknown]', '`3000109` 3000109', '[/unknown]', ''].join(eol);
|
|
}
|
|
describe('商城结构和编辑', () => {
|
|
it('识别三种布局、导航顺序及聚合页签', () => {
|
|
const doc = readCeraShop(fixture());
|
|
expect(doc.issues).toEqual([]); expect(doc.products).toHaveLength(3);
|
|
expect(doc.tabs).toEqual(['event','mileage','hotandnew','package','avatar','item','exit']);
|
|
expect(doc.products.find(p => p.section === 'package')).toMatchObject({ name: 'Summer Box', cash: '599', date: '20241105' });
|
|
expect(doc.products.find(p => p.section === 'dont trade avatar')).toMatchObject({ name: '', cash: '120' });
|
|
expect(ceraTabProducts(doc, 'hotandnew').map(p => p.id)).toEqual(['3000109']);
|
|
expect(ceraTabProducts(doc, 'mileage').map(p => p.id)).toEqual(['3000109']);
|
|
expect(ceraDate('20241105')).toBe('2024-11-05');
|
|
});
|
|
for (const eol of ['\n', '\r\n', '\r']) {
|
|
it(`逐字段编辑保留未知字段、注释和换行 ${JSON.stringify(eol)}`, () => {
|
|
const source = fixture(eol).replace('1 1 0 0 15', '1 1 # 价格注释'+eol+' 0 0 15');
|
|
const row = readCeraShop(source).products.find(p => p.section === 'item')!, values = row.fields.map(t => t.value);
|
|
values[5] = '30'; values[8] = '中文 `名称`';
|
|
const result = changeCeraProduct(source, 'edit', 'item', values, row);
|
|
expect(result).toBe(source.replace('0 0 15', '0 0 30').replace('`Life Token`', '`中文 ``名称```'));
|
|
expect(readCeraShop(result).products.find(p => p.section === 'item')?.name).toBe('中文 `名称`');
|
|
});
|
|
it(`改号和删除同步商品引用,但保留物品编号 ${JSON.stringify(eol)}`, () => {
|
|
const source = fixture(eol), row = readCeraShop(source).products.find(p => p.section === 'item')!, values = row.fields.map(t => t.value);
|
|
values[0] = '3000999';
|
|
const result = changeCeraProduct(source, 'edit', 'item', values, row), doc = readCeraShop(result);
|
|
expect(doc.products.find(p => p.id === '3000999')?.itemId).toBe('1');
|
|
expect(ceraTabProducts(doc, 'hotandnew')[0]?.id).toBe('3000999');
|
|
expect(result).toContain('[unknown]'+eol+'`3000109` 3000109');
|
|
expect(result).toContain('3000999 1'); expect(result).toContain('1 3000999');
|
|
const removed = changeCeraProduct(source, 'delete', 'item', [], row), after = readCeraShop(removed);
|
|
expect(after.products).toHaveLength(2); expect(after.sections.find(s => s.name === 'purchasing limit')?.tokens).toEqual([]);
|
|
expect(after.sections.find(s => s.name === 'storage')?.children).toHaveLength(1);
|
|
expect(after.sections.find(s => s.name === 'visible storage')?.children).toHaveLength(0);
|
|
expect(removed).toContain('3400245 590713421'); expect(removed).toContain('[unknown]'+eol+'`3000109` 3000109');
|
|
});
|
|
}
|
|
it('新增自动递增、允许手动编号,缺少分类时追加分类', () => {
|
|
const source = fixture(), doc = readCeraShop(source);
|
|
expect(nextCeraID(doc)).toBe('3400246');
|
|
const values = newCeraValues(doc, 'item event'); values[1] = '42';
|
|
const result = changeCeraProduct(source, 'add', 'item event', values);
|
|
expect(result.startsWith(source)).toBe(true);
|
|
expect(readCeraShop(result).products.find(p => p.section === 'item event')).toMatchObject({ id: '3400246', itemId: '42', cash: '0' });
|
|
values[0] = '3500000'; expect(readCeraShop(changeCeraProduct(source, 'add', 'item', values)).products).toHaveLength(4);
|
|
});
|
|
it('保留特殊类型字符串标记', () => {
|
|
const source = fixture().replace('`Life Token`', '{7=`Life Token`}');
|
|
const target = readCeraShop(source).products.find(p => p.section === 'item')!, next = target.fields.map(t => t.value); next[8] = '新名称';
|
|
expect(changeCeraProduct(source, 'edit', 'item', next, target)).toContain('{7=`新名称`}');
|
|
});
|
|
it('拒绝重复编号、无效数值、失效目标和不完整记录', () => {
|
|
const source = fixture(), doc = readCeraShop(source), row = doc.products.find(p => p.section === 'item')!, values = row.fields.map(t => t.value);
|
|
for (const value of ['3400245', '0', '-1', '2147483648', '1.5', '']) { values[0] = value; expect(() => changeCeraProduct(source,'edit','item',values,row)).toThrow(); }
|
|
values[0] = row.id; values[5] = '-1'; expect(() => changeCeraProduct(source,'edit','item',values,row)).toThrow();
|
|
expect(() => changeCeraProduct('# shift\n'+source,'delete','item',[],row)).toThrow('已变化');
|
|
const broken = source.replace(item, item + ' 9'), parsed = readCeraShop(broken);
|
|
expect(parsed.blocked.has('item')).toBe(true); expect(() => newCeraValues(parsed,'item')).toThrow(); expect(() => nextCeraID(parsed)).toThrow();
|
|
expect(() => changeCeraProduct(source.replace('3000109 1 0 2 0 0 0 0', '3000109 1'), 'delete', 'item', [], row)).toThrow();
|
|
});
|
|
it('可交易时装独立使用 13 字段布局', () => {
|
|
const source = '[avatar]\n4000114 39000 1 0 0 700 0 0 90 0 -1 -1 ``\n[/avatar]';
|
|
const doc = readCeraShop(source); expect(doc.issues).toEqual([]);
|
|
expect(doc.products[0]).toMatchObject({ id: '4000114', cash: '700', name: '' });
|
|
const values = newCeraValues(doc, 'avatar'); values[1] = '39003';
|
|
expect(values).toHaveLength(13); expect(values[12]).toBe('');
|
|
expect(readCeraShop(changeCeraProduct(source, 'add', 'avatar', values)).products).toHaveLength(2);
|
|
});
|
|
it('入口准确识别商城文件', () => {
|
|
const file = (path: string) => ({ index: 1, path, text: '', editable: true });
|
|
expect(getGUIProvider(file('etc/(r)cerashop.etc'))?.id).toBe('cera-shop');
|
|
expect(getGUIProvider(file('ETC\\(R)CERASHOP.ETC'))?.id).toBe('cera-shop');
|
|
expect(getGUIProvider(file('etc/cerashopoption.cos'))).toBeNull();
|
|
});
|
|
it('兼容 90CN 按钮顺序的历史结束标签,编辑保留原始拼写', () => {
|
|
const source = fixture().replace('[/shop button list and sequence]', '[/shop button and sequence]');
|
|
const doc = readCeraShop(source);
|
|
expect(doc.tabs).toEqual(['event','mileage','hotandnew','package','avatar','item','exit']);
|
|
expect(doc.issues).toEqual([]);
|
|
const row = doc.products.find(p => p.section === 'item')!, values = row.fields.map(t => t.value); values[5] = '42';
|
|
const edited = changeCeraProduct(source, 'edit', 'item', values, row);
|
|
expect(edited).toBe(source.replace('0 0 15', '0 0 42'));
|
|
expect(edited).toContain('[/shop button and sequence]');
|
|
expect(() => readCeraShop(fixture().replace('[/item]', '[/wrong item]'))).toThrow('闭合标签不匹配');
|
|
});
|
|
function legacyFixture(eol = '\n') {
|
|
return ['# 旧版商城 😀', '[avatar]', '120000 39032 1 1 0 -1', '[/avatar]',
|
|
'[coin]', '100000 1 10 0 0 880 `10个` 0 0', '[/coin]',
|
|
'[item]', '100534 2681921 1 0 0 2000 `账号金库升级工具` 0 0', '[/item]',
|
|
'[selectable character premium]', '-1 2681927 -1 7 0 2000 `魔王之契约` 0 -1', '[/selectable character premium]',
|
|
'[visual]', '100615 2681313 -1 7 0 300 `名称装饰卡 (7天)` 0', '[/visual]',
|
|
'[package]', '104763 490702435 0 0 19800 `夏日礼包` 1 0 -1 -1 15', '[/package]',
|
|
'[community item]', '102401 2683401 1 0 0 14888 `1个` 101 0', '[/community item]',
|
|
'[charac premium package]', '100625 2682006 3880 `60天` 0 0 1 60 100614', '[/charac premium package]',
|
|
'[derivative]', '`https://example.invalid/item` `周边` 338 -1 -1 5 -1', '[/derivative]',
|
|
'[shop button list and sequence]', '`mileage` `hotandnew` `package` `avatar` `item` `community` `derivative` `exit`', '[/shop button list and sequence]',
|
|
'[buy restrict item]', '1 100534 7 1', '[/buy restrict item]',
|
|
'[btn control]', '100534 0 1 0', '[/btn control]',
|
|
'[default promotion page]', '100534 29 -1 7', '[/default promotion page]',
|
|
'[specific product mileage]', '100534 3', '[/specific product mileage]',
|
|
'[custom]', '100534 `保留`', '[/custom]', ''].join(eol);
|
|
}
|
|
it('按结构识别普通版商城,保留旧版页签及各分类', () => {
|
|
const doc = readCeraShop(legacyFixture());
|
|
expect(doc.family).toBe('legacy'); expect(doc.issues).toEqual([]); expect(doc.products).toHaveLength(9);
|
|
expect(doc.tabs).toEqual(['mileage','hotandnew','package','avatar','item','community','derivative','exit']);
|
|
expect(doc.schemas.item).toMatchObject({ width: 9, name: 6, date: -1 });
|
|
expect(doc.products.find(p => p.section === 'avatar')).toMatchObject({ gold: '', cash: '', quantity: '' });
|
|
expect(doc.products.find(p => p.section === 'selectable character premium')).toMatchObject({ gold: '', quantity: '', cash: '2000' });
|
|
expect(doc.products.find(p => p.section === 'visual')).toMatchObject({ gold: '', quantity: '', cash: '300' });
|
|
expect(doc.products.find(p => p.section === 'charac premium package')).toMatchObject({ cash: '3880', name: '60天' });
|
|
expect(ceraTabProducts(doc, 'community')).toHaveLength(1);
|
|
expect(ceraTabProducts(doc, 'derivative')[0]).toMatchObject({ id: '', itemId: '-1', name: '周边', cash: '338' });
|
|
expect(() => newCeraValues(doc, 'derivative')).toThrow();
|
|
expect(() => changeCeraProduct(legacyFixture(), 'delete', 'derivative', [], ceraTabProducts(doc, 'derivative')[0])).toThrow();
|
|
});
|
|
for (const eol of ['\n','\r\n','\r']) {
|
|
it(`普通版增删改保留字段宽度、期限及引用 ${JSON.stringify(eol)}`, () => {
|
|
const source = legacyFixture(eol), doc = readCeraShop(source), row = doc.products.find(p => p.section === 'item')!;
|
|
const values = row.fields.map(t => t.value); values[0] = '100535'; values[5] = '1234';
|
|
const changed = changeCeraProduct(source,'edit','item',values,row), after = readCeraShop(changed);
|
|
expect(after.products.find(p => p.section === 'item')).toMatchObject({ id: '100535', cash: '1234' });
|
|
expect(changed).toContain('1 100535 7 1'); expect(changed).toContain('100535 29 -1 7');
|
|
expect(changed).toContain('[custom]'+eol+'100534 `保留`');
|
|
expect(changed).toContain('100615 2681313 -1 7 0 300');
|
|
const removed = readCeraShop(changeCeraProduct(source,'delete','item',[],row));
|
|
expect(removed.sections.find(s => s.name === 'buy restrict item')?.tokens).toHaveLength(0);
|
|
expect(removed.sections.find(s => s.name === 'btn control')?.tokens).toHaveLength(0);
|
|
expect(removed.sections.find(s => s.name === 'default promotion page')?.tokens.map(t => t.value)).toEqual(['-1','7']);
|
|
for (const name of ['avatar','item','package','visual','charac premium package']) {
|
|
const fields = newCeraValues(doc,name); fields[1] = '42';
|
|
const added = readCeraShop(changeCeraProduct(source,'add',name,fields));
|
|
expect(added.products).toHaveLength(10); expect(fields).toHaveLength(doc.schemas[name]!.width);
|
|
}
|
|
expect(nextCeraID(doc)).toBe('120001');
|
|
});
|
|
}
|
|
const legacyPath = process.env.PVF_CERA90_LEGACY_TEXT;
|
|
it.skipIf(!legacyPath || !existsSync(legacyPath!))('90CN etc/cerashop.etc 真实样本显示所有商品并使用原布局增删改', () => {
|
|
const source = readFileSync(legacyPath!, 'utf8'), doc = readCeraShop(source);
|
|
expect(doc.family).toBe('legacy'); expect(doc.issues).toEqual([]); expect(doc.blocked.size).toBe(0);
|
|
expect(doc.products).toHaveLength(37127);
|
|
expect(ceraTabProducts(doc,'avatar')).toHaveLength(36394);
|
|
expect(ceraTabProducts(doc,'item')).toHaveLength(239);
|
|
expect(ceraTabProducts(doc,'package')).toHaveLength(453);
|
|
expect(ceraTabProducts(doc,'community')).toHaveLength(34);
|
|
expect(ceraTabProducts(doc,'derivative')).toHaveLength(7);
|
|
for (const name of ['avatar','item','coin','material','recoveryitem','premium','selectable character premium','visual','creature','community package','community item','regular package','package','charac premium package']) {
|
|
const row = doc.products.find(p => p.section === name && Number(p.id) > 0)!, schema = doc.schemas[name]!, values = row.fields.map(t => t.value);
|
|
const column = schema.cash >= 0 ? schema.cash : 2; values[column] = schema.cash >= 0 ? '123' : '2';
|
|
const changed = changeCeraProduct(source,'edit',name,values,row);
|
|
const token = row.fields[column]!;
|
|
expect(changed).toBe(source.slice(0,token.start)+values[column]+source.slice(token.end));
|
|
const fields = newCeraValues(doc,name); fields[1] = row.itemId;
|
|
expect(readCeraShop(changeCeraProduct(source,'add',name,fields)).products).toHaveLength(37128);
|
|
}
|
|
const target = doc.products.find(p => p.section === 'item')!, values = target.fields.map(t => t.value); values[0] = nextCeraID(doc);
|
|
expect(readCeraShop(changeCeraProduct(source,'edit','item',values,target)).products.find(p => p.id === values[0])).toBeDefined();
|
|
expect(readCeraShop(changeCeraProduct(source,'delete','item',[],target)).products).toHaveLength(37126);
|
|
});
|
|
function twFixture() {
|
|
return ['# TW 商城 😀', '[npc info]', '`Map/Npc/NpcFace01.img` 12', '[/npc info]',
|
|
'[avatar]', '[/avatar]', '[dont trade avatar]', '[/dont trade avatar]', '[avatar dye]', '[/avatar dye]',
|
|
'[coin]', '9000 1 1 0 0 5 `复活币` 0 0 -1', '[/coin]',
|
|
'[item]', '10000 50 1 0 0 10 `金库升级` 0 0 -1', '[/item]',
|
|
'[premium]', '30001 31 1 0 0 50 `契约` 0 0 -1', '[/premium]',
|
|
'[creature]', '20000 24 100 0 0 30 `宠物饲料` 0 0 -1', '[/creature]',
|
|
'[package]', '100031 2660041 0 0 1080 `礼包` 2 0 -1 -1', '[/package]',
|
|
'[gift disallowance]', '10000', '[/gift disallowance]',
|
|
'[shop button list and sequence]', '`hotandnew` `avatar` `item` `creature` `package` `exit`', '[/shop button list and sequence]', ''].join('\n');
|
|
}
|
|
it('TW 使用十字段道具和礼包,宠物按配置显示独立页签', () => {
|
|
const doc = readCeraShop(twFixture());
|
|
expect(doc.family).toBe('tw'); expect(doc.issues).toEqual([]); expect(doc.products).toHaveLength(5);
|
|
expect(doc.schemas.item).toMatchObject({ width:10, name:6, date:-1 });
|
|
expect(doc.schemas.package).toMatchObject({ width:10, name:5, date:-1 });
|
|
expect(doc.schemas.avatar.width).toBe(7); expect(doc.schemas['dont trade avatar'].width).toBe(8);
|
|
expect(doc.schemas['avatar dye']).toBeUndefined();
|
|
expect(doc.tabs).toEqual(['hotandnew','avatar','item','creature','package','exit']);
|
|
expect(ceraTabProducts(doc,'item')).toHaveLength(3); expect(ceraTabProducts(doc,'creature')).toHaveLength(1);
|
|
expect(doc.products.find(p => p.section === 'creature')).toMatchObject({ cash:'30', quantity:'100' });
|
|
expect(nextCeraID(doc)).toBe('100032');
|
|
const row = doc.products.find(p => p.section === 'item')!, values=row.fields.map(t=>t.value); values[0]='100032'; values[5]='20';
|
|
const changed=changeCeraProduct(twFixture(),'edit','item',values,row);
|
|
expect(changed).toContain('[gift disallowance]\n100032');
|
|
expect(changed).toContain('`Map/Npc/NpcFace01.img` 12');
|
|
expect(readCeraShop(changed).products.find(p=>p.id==='100032')).toMatchObject({cash:'20',name:'金库升级'});
|
|
for(const name of ['avatar','dont trade avatar','coin','item','premium','creature','package']) {
|
|
const fields=newCeraValues(doc,name); fields[1]='42';
|
|
expect(readCeraShop(changeCeraProduct(twFixture(),'add',name,fields)).products).toHaveLength(6);
|
|
expect(fields).toHaveLength(doc.schemas[name]!.width);
|
|
}
|
|
});
|
|
it('TW 七/八字段时装保留原始期限与附加参数,不误作价格或数量', () => {
|
|
const source='[avatar]\n144327 39000 1 90 0 -1 -1\n[/avatar]\n[dont trade avatar]\n55309429 101500454 4 0 0 -1 120164 -1\n[/dont trade avatar]';
|
|
const doc=readCeraShop(source); expect(doc.family).toBe('tw'); expect(doc.issues).toEqual([]);
|
|
expect(doc.products).toHaveLength(2);
|
|
for(const row of doc.products) {
|
|
expect(row).toMatchObject({gold:'',cash:'',quantity:''});
|
|
const values=row.fields.map(t=>t.value); values[2]='2';
|
|
const token=row.fields[2]!;
|
|
expect(changeCeraProduct(source,'edit',row.section,values,row)).toBe(source.slice(0,token.start)+'2'+source.slice(token.end));
|
|
}
|
|
});
|
|
for(const [variable,count] of [['PVF_CERA_TW_TEXT',133],['PVF_CERA_TW_FIRST_TEXT',54476]] as const) {
|
|
const path=process.env[variable];
|
|
it.skipIf(!path || !existsSync(path!))(`TW 真实商城回归 ${variable}`,()=>{
|
|
const source=readFileSync(path!,'utf8'),doc=readCeraShop(source);
|
|
expect(doc.family).toBe('tw'); expect(doc.blocked.size).toBe(0); expect(doc.products).toHaveLength(count);
|
|
expect(doc.issues).toEqual([]);
|
|
expect(doc.tabs).toContain('creature');
|
|
expect(ceraTabProducts(doc,'creature')).toHaveLength(count===133?5:17);
|
|
if(count===133)expect(ceraTabProducts(doc,'item')).toHaveLength(96);
|
|
for(const name of ['coin','item','premium','creature','package']) {
|
|
const row=doc.products.find(p=>p.section===name && Number(p.id)>0)!,schema=doc.schemas[name]!,values=row.fields.map(t=>t.value);
|
|
values[schema.cash]='123'; const token=row.fields[schema.cash]!;
|
|
expect(changeCeraProduct(source,'edit',name,values,row)).toBe(source.slice(0,token.start)+'123'+source.slice(token.end));
|
|
const added=newCeraValues(doc,name);added[1]=row.itemId;
|
|
expect(readCeraShop(changeCeraProduct(source,'add',name,added)).products).toHaveLength(count+1);
|
|
expect(readCeraShop(changeCeraProduct(source,'delete',name,[],row)).products).toHaveLength(count-1);
|
|
}
|
|
});
|
|
}
|
|
const real90Path = process.env.PVF_CERA90_TEXT;
|
|
it.skipIf(!real90Path || !existsSync(real90Path!))('90CN 真实商城可以解析并修改四种记录的价格', () => {
|
|
const source = readFileSync(real90Path!, 'utf8'), doc = readCeraShop(source);
|
|
expect(doc.blocked.size).toBe(0);
|
|
expect(doc.tabs).toEqual(['event','mileage','hotandnew','package','avatar','item','exit']);
|
|
expect(doc.products.length).toBeGreaterThan(60000);
|
|
for (const section of ['item','avatar','dont trade avatar','package']) {
|
|
const row = doc.products.find(p => p.section === section && Number(p.id) > 0)!, values = row.fields.map(t => t.value); values[ceraSchemas[section]!.cash] = '123';
|
|
const changed = changeCeraProduct(source, 'edit', section, values, row);
|
|
expect(changed).toContain('[/shop button and sequence]');
|
|
expect(readCeraShop(changed).products.find(p => p.section === section && p.row === row.row)?.cash).toBe('123');
|
|
}
|
|
});
|
|
const realPath = process.env.PVF_CERA_TEXT;
|
|
it.skipIf(!realPath || !existsSync(realPath!))('110US 真实样本分组、改价、增删与引用更新', () => {
|
|
const source = readFileSync(realPath!, 'utf8'), doc = readCeraShop(source);
|
|
expect(doc.products).toHaveLength(17091); expect(doc.issues).toEqual([]);
|
|
expect(doc.products.filter(p => p.section === 'dont trade avatar')).toHaveLength(10755);
|
|
expect(doc.products.filter(p => p.section === 'package')).toHaveLength(5120);
|
|
for (const section of ['item','dont trade avatar','package']) {
|
|
const row = doc.products.find(p => p.section === section)!, values = row.fields.map(t => t.value); values[ceraSchemas[section]!.cash] = '123';
|
|
expect(readCeraShop(changeCeraProduct(source,'edit',section,values,row)).products.find(p => p.id === row.id)?.cash).toBe('123');
|
|
expect(readCeraShop(changeCeraProduct(source,'delete',section,[],row)).products).toHaveLength(17090);
|
|
}
|
|
const values = newCeraValues(doc,'item'); values[1]='1';
|
|
expect(readCeraShop(changeCeraProduct(source,'add','item',values)).products).toHaveLength(17092);
|
|
});
|
|
});
|