Support explicit current-output A/B fill, protected edited drafts, scoped cloud update offers and atomic native restore with stale-open CAS. Preserve original unknown requests, improve Pi conversation continuity and native DPI/navigation reads, and publish the authenticated template metadata contract. Validated: native backend 172 passed/5 environment tests ignored, UI 110, Pi 53, template/rule API 24 and native cloud contract 6; strict Clippy, layering and wasm. Real S01 selected B, edited/undo-redo, PCraft reopen and layered PSD roundtrip pass with exact pixels. Full nine-output generation and Photoshop acceptance remain open.
52 lines
3.3 KiB
TypeScript
52 lines
3.3 KiB
TypeScript
/** @jest-environment node */
|
|
import { desktopAgentRules } from '../desktop-client/agent-rules'
|
|
import { createHash } from 'node:crypto'
|
|
import { emptyBrief, validateBrief } from '../desktop-client/creation.mjs'
|
|
describe('desktop Agent versioned rule catalog', () => {
|
|
test('lists only real ready combinations and returns an exact scoped package', () => {
|
|
const index = desktopAgentRules(null) as any
|
|
expect(index.items).toHaveLength(2)
|
|
expect(index.items[0].label).toBe('顾家 · 电脑桌')
|
|
const selected = desktopAgentRules(index.items[0].id) as any
|
|
expect(selected.catalog.brands).toHaveLength(1)
|
|
expect(selected.catalog.shops[0].id).toBe(index.items[0].shopId)
|
|
expect(selected.catalog.categories[0].id).toBe(index.items[0].categoryId)
|
|
expect(selected.catalog.bindings).toHaveLength(1)
|
|
const canonical = JSON.stringify(selected.catalog, (_, item) => item && typeof item === 'object' && !Array.isArray(item)
|
|
? Object.fromEntries(Object.keys(item).sort().map(key => [key,item[key]])) : item)
|
|
expect(selected.contentHash).toBe(createHash('sha256').update(canonical).digest('hex'))
|
|
expect(index.items[0].contentHash).toBe(selected.contentHash)
|
|
expect(index.items[0].projectBrandId).toBe(index.items[0].shopId)
|
|
expect(index.categories.some((c: any) => c.name === '化妆台')).toBe(true)
|
|
expect(index.items.some((c: any) => c.categoryName === '化妆台')).toBe(false)
|
|
expect(() => desktopAgentRules('unknown')).toThrow('尚未配置')
|
|
expect(() => desktopAgentRules('../other')).toThrow('编号无效')
|
|
})
|
|
test('Yijiada rules use their own official brand and cannot inherit Gujia branding', () => {
|
|
const index = desktopAgentRules(null) as any
|
|
const gujia = index.items.find((item: any) => item.id === 'GJ-DESK-DNZ0385')
|
|
const yijiada = index.items.find((item: any) => item.id === 'YJD-DESK-DNZ0385-NATIVE')
|
|
expect(yijiada.label).toBe('亿家达 · 电脑桌')
|
|
expect(yijiada.projectBrandId).toBe('2c6d91fd-5a7f-4e95-adcc-7f4437c6772b')
|
|
expect(yijiada.projectBrandId).not.toBe(gujia.projectBrandId)
|
|
const selected = desktopAgentRules(yijiada.id) as any
|
|
expect(selected.catalog.brands).toHaveLength(1)
|
|
expect(selected.catalog.brands[0]).toMatchObject({ id: yijiada.brandId, name: '亿家达' })
|
|
expect(selected.catalog.shops).toHaveLength(1)
|
|
expect(selected.catalog.shops[0]).toMatchObject({ id: yijiada.projectBrandId, name: '亿家达' })
|
|
expect(selected.catalog.bindings).toHaveLength(1)
|
|
expect(selected.catalog.bindings[0].id).toBe(yijiada.id)
|
|
expect(JSON.stringify(selected.catalog)).not.toContain(gujia.brandId)
|
|
expect(JSON.stringify(selected.catalog)).not.toContain(gujia.projectBrandId)
|
|
expect(selected.contentHash).toBe(yijiada.contentHash)
|
|
expect(selected.contentHash).not.toBe(gujia.contentHash)
|
|
})
|
|
test('old briefs keep an empty category, while an explicit category survives cloud validation', () => {
|
|
const old = emptyBrief() as any
|
|
delete old.categoryId; delete old.categoryName
|
|
expect(validateBrief(old)).toMatchObject({ categoryId: '', categoryName: '' })
|
|
expect(validateBrief({ ...old, categoryId: 'real-category', categoryName: '电脑桌' })).toMatchObject({ categoryId: 'real-category', categoryName: '电脑桌' })
|
|
expect(() => validateBrief({ ...old, categoryId: false })).toThrow('品类格式无效')
|
|
})
|
|
})
|