import assert from 'node:assert/strict' ;(async () => { const mod = await import('../utils/oa-app-icons.js') const { OA_APP_ICON_COLOR_PAIRS, resolveOaAppIcon, parseEpIconUrl, buildEpIconUrl, isEpIconUrl, epIconDataUri } = mod assert.strictEqual(OA_APP_ICON_COLOR_PAIRS.length, 8) assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[0].bg, '#d1fae5') assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[0].fg, '#059669') assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[2].bg, '#dbeafe') assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[2].fg, '#2563eb') assert.strictEqual(isEpIconUrl('ep:Calendar|#dbeafe'), true) assert.strictEqual(isEpIconUrl('https://x/a.png'), false) const p = parseEpIconUrl('ep:Calendar|#dbeafe') assert.strictEqual(p.icon, 'Calendar') assert.strictEqual(p.bg, '#dbeafe') assert.strictEqual(p.fg, '#2563eb') const bad = parseEpIconUrl('ep:NoSuch|#zzzzzz') assert.strictEqual(bad.icon, 'Document') assert.strictEqual(bad.bg, '#d1fae5') assert.strictEqual(bad.fg, '#059669') const empty = resolveOaAppIcon('') assert.strictEqual(empty.kind, 'ep') assert.strictEqual(empty.icon, 'Document') assert.strictEqual(empty.bg, '#d1fae5') const img = resolveOaAppIcon('https://cdn.example/a.png') assert.strictEqual(img.kind, 'image') assert.strictEqual(img.src, 'https://cdn.example/a.png') const legacy = resolveOaAppIcon('/oa-app-icons/doc-orange.svg') assert.strictEqual(legacy.kind, 'image') assert.strictEqual(legacy.src, '/static/oa-app-icons/doc-orange.svg') const uploaded = resolveOaAppIcon('202608/11/c73acbdede3749b1b81cd7349c7c03fa.png') assert.strictEqual(uploaded.kind, 'image') assert.ok( String(uploaded.src).endsWith('/202608/11/c73acbdede3749b1b81cd7349c7c03fa.png'), 'uploaded MinIO key should keep object path' ) assert.ok( /^https?:\/\//i.test(uploaded.src), 'uploaded MinIO key should resolve to absolute URL' ) const built = buildEpIconUrl('Wallet', '#fef3c7') assert.strictEqual(built, 'ep:Wallet|#fef3c7') const r = resolveOaAppIcon(built) assert.strictEqual(r.kind, 'ep') assert.strictEqual(r.fg, '#d97706') const withBtoa = epIconDataUri('Calendar', '#2563eb') assert.strictEqual(withBtoa.startsWith('data:image/svg+xml;base64,'), true) assert.ok(!withBtoa.includes('undefined'), 'data uri must not contain undefined') // 模拟微信 appservice:无 btoa、无 Buffer const savedBtoa = globalThis.btoa const savedBuffer = globalThis.Buffer try { // eslint-disable-next-line no-global-assign globalThis.btoa = undefined // eslint-disable-next-line no-global-assign globalThis.Buffer = undefined const noBtoa = epIconDataUri('Money', '#db2777') assert.strictEqual(noBtoa.startsWith('data:image/svg+xml;base64,'), true) assert.ok(noBtoa.length > 40, 'fallback base64 should produce payload') const office = epIconDataUri('OfficeBuilding', '#0891b2') assert.strictEqual(office.startsWith('data:image/svg+xml;base64,'), true) } finally { if (savedBtoa !== undefined) globalThis.btoa = savedBtoa else delete globalThis.btoa if (savedBuffer !== undefined) globalThis.Buffer = savedBuffer else delete globalThis.Buffer } console.log('ok: oa-app-icons checks passed') })().catch((e) => { console.error('FAIL:', e.message || e) process.exit(1) })