check-oa-app-icons.js 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import assert from 'node:assert/strict'
  2. ;(async () => {
  3. const mod = await import('../utils/oa-app-icons.js')
  4. const {
  5. OA_APP_ICON_COLOR_PAIRS,
  6. resolveOaAppIcon,
  7. parseEpIconUrl,
  8. buildEpIconUrl,
  9. isEpIconUrl,
  10. epIconDataUri
  11. } = mod
  12. assert.strictEqual(OA_APP_ICON_COLOR_PAIRS.length, 8)
  13. assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[0].bg, '#d1fae5')
  14. assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[0].fg, '#059669')
  15. assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[2].bg, '#dbeafe')
  16. assert.strictEqual(OA_APP_ICON_COLOR_PAIRS[2].fg, '#2563eb')
  17. assert.strictEqual(isEpIconUrl('ep:Calendar|#dbeafe'), true)
  18. assert.strictEqual(isEpIconUrl('https://x/a.png'), false)
  19. const p = parseEpIconUrl('ep:Calendar|#dbeafe')
  20. assert.strictEqual(p.icon, 'Calendar')
  21. assert.strictEqual(p.bg, '#dbeafe')
  22. assert.strictEqual(p.fg, '#2563eb')
  23. const bad = parseEpIconUrl('ep:NoSuch|#zzzzzz')
  24. assert.strictEqual(bad.icon, 'Document')
  25. assert.strictEqual(bad.bg, '#d1fae5')
  26. assert.strictEqual(bad.fg, '#059669')
  27. const empty = resolveOaAppIcon('')
  28. assert.strictEqual(empty.kind, 'ep')
  29. assert.strictEqual(empty.icon, 'Document')
  30. assert.strictEqual(empty.bg, '#d1fae5')
  31. const img = resolveOaAppIcon('https://cdn.example/a.png')
  32. assert.strictEqual(img.kind, 'image')
  33. assert.strictEqual(img.src, 'https://cdn.example/a.png')
  34. const legacy = resolveOaAppIcon('/oa-app-icons/doc-orange.svg')
  35. assert.strictEqual(legacy.kind, 'image')
  36. assert.strictEqual(legacy.src, '/static/oa-app-icons/doc-orange.svg')
  37. const uploaded = resolveOaAppIcon('202608/11/c73acbdede3749b1b81cd7349c7c03fa.png')
  38. assert.strictEqual(uploaded.kind, 'image')
  39. assert.ok(
  40. String(uploaded.src).endsWith('/202608/11/c73acbdede3749b1b81cd7349c7c03fa.png'),
  41. 'uploaded MinIO key should keep object path'
  42. )
  43. assert.ok(
  44. /^https?:\/\//i.test(uploaded.src),
  45. 'uploaded MinIO key should resolve to absolute URL'
  46. )
  47. const built = buildEpIconUrl('Wallet', '#fef3c7')
  48. assert.strictEqual(built, 'ep:Wallet|#fef3c7')
  49. const r = resolveOaAppIcon(built)
  50. assert.strictEqual(r.kind, 'ep')
  51. assert.strictEqual(r.fg, '#d97706')
  52. const withBtoa = epIconDataUri('Calendar', '#2563eb')
  53. assert.strictEqual(withBtoa.startsWith('data:image/svg+xml;base64,'), true)
  54. assert.ok(!withBtoa.includes('undefined'), 'data uri must not contain undefined')
  55. // 模拟微信 appservice:无 btoa、无 Buffer
  56. const savedBtoa = globalThis.btoa
  57. const savedBuffer = globalThis.Buffer
  58. try {
  59. // eslint-disable-next-line no-global-assign
  60. globalThis.btoa = undefined
  61. // eslint-disable-next-line no-global-assign
  62. globalThis.Buffer = undefined
  63. const noBtoa = epIconDataUri('Money', '#db2777')
  64. assert.strictEqual(noBtoa.startsWith('data:image/svg+xml;base64,'), true)
  65. assert.ok(noBtoa.length > 40, 'fallback base64 should produce payload')
  66. const office = epIconDataUri('OfficeBuilding', '#0891b2')
  67. assert.strictEqual(office.startsWith('data:image/svg+xml;base64,'), true)
  68. } finally {
  69. if (savedBtoa !== undefined) globalThis.btoa = savedBtoa
  70. else delete globalThis.btoa
  71. if (savedBuffer !== undefined) globalThis.Buffer = savedBuffer
  72. else delete globalThis.Buffer
  73. }
  74. console.log('ok: oa-app-icons checks passed')
  75. })().catch((e) => {
  76. console.error('FAIL:', e.message || e)
  77. process.exit(1)
  78. })