Files
danyang-match/ui-tests/tabbar-icons.mjs
T
WorkBuddy 1ad9793ea2 重构底部导航图标:照参考图重做形状与配色
- 5 个 Tab 图标形状改为参考图语言:房子(首页)/爱心(找对象)/对话气泡(消息)/日历加号(活动)/人物(我的)
- 配色改为参考图方案:默认态藏青蓝 #47528C、选中态玫红 #F4005A(与导航栏品牌色同系)
- 同步重生成 1x/2x/3x 共 30 张透明 RGBA PNG(Edge CDP 栅格化)
- app.json tabBar.color/selectedColor 对齐新配色
- 守卫 tabbar-icons.mjs 增加两态颜色与 app.json 一致性断言
- 静态预览复刻 tabBar 配色同步更新;DESIGN.md 同步
2026-09-23 16:30:32 +08:00

123 lines
6.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict'
import { readFileSync, existsSync } from 'node:fs'
import { join } from 'node:path'
const repoRoot = process.cwd()
const root = join(repoRoot, 'miniapp', 'assets', 'tabbar')
const icons = {
home: '房子',
discover: '爱心',
message: '对话气泡',
activity: '日历',
mine: '人物',
}
// ── 1. SVG 源文件:主题化标题 + 两态配色 ──────────────────────────────
for (const [name, title] of Object.entries(icons)) {
const normal = readFileSync(join(root, 'svg', `${name}.svg`), 'utf8')
const active = readFileSync(join(root, 'svg', `${name}-active.svg`), 'utf8')
assert.match(normal, new RegExp(`<title>${title}</title>`), `${name} 缺少主题化标题`)
assert.match(normal, /#47528C/i, `${name} 默认态颜色错误`)
assert.match(active, /#F4005A/i, `${name} 选中态颜色错误`)
// ── 2. PNG 规格:正方形、1x/2x/3x、透明 RGBA ────────────────────────
for (const suffix of ['', '_2x', '_3x']) {
const expectedSize = suffix === '' ? 81 : suffix === '_2x' ? 162 : 243
for (const state of ['', '-active']) {
const png = readFileSync(join(root, `${name}${state}${suffix}.png`))
assert.equal(png.readUInt32BE(16), expectedSize)
assert.equal(png.readUInt32BE(20), expectedSize)
assert.equal(png[25], 6, `${name}${state}${suffix} 必须为透明 RGBA PNG`)
}
}
}
// ── 3. app.json ↔ 磁盘一致性 ─────────────────────────────────────────
// 历史缺陷:tabBar 图标只被 app.json 引用(不经 WXML/JS),
// 一旦配置漂移,不会有任何 WXML 侧症状,只会「底部导航整排变破图」。
const appJsonPath = join(repoRoot, 'miniapp', 'app.json')
const appJson = JSON.parse(readFileSync(appJsonPath, 'utf8'))
const tabList = appJson.tabBar?.list ?? []
assert.equal(tabList.length, 5, 'tabBar.list 必须为 5 项(微信支持 2~5)')
// 文字与图标同色:color 必须等于 SVG 默认态色,selectedColor 必须等于选中态色,
// 否则会出现「图标是藏青蓝/玫红、文字却是别的颜色」的割裂。
assert.equal(appJson.tabBar?.color, '#47528C', 'tabBar.color 必须与图标默认态同色(#47528C)')
assert.equal(appJson.tabBar?.selectedColor, '#F4005A', 'tabBar.selectedColor 必须与图标选中态同色(#F4005A)')
for (const item of tabList) {
assert.ok(appJson.pages.includes(item.pagePath), `tabBar pagePath 未在 pages 中注册: ${item.pagePath}`)
for (const key of ['iconPath', 'selectedIconPath']) {
const rel = item[key]
assert.ok(rel, `tabBar ${item.pagePath} 缺少 ${key}`)
assert.ok(!rel.startsWith('/'), `tabBar ${key} 不应以 / 开头(微信按小程序根解析): ${rel}`)
assert.ok(
existsSync(join(repoRoot, 'miniapp', rel)),
`tabBar ${key} 指向不存在的文件: ${rel}`,
)
}
}
// ── 4. 「无依赖文件过滤」必须关闭(tabBar 图标整排变破图的根因)────────
// 微信开发者工具自 1.05.2112301 起默认开启该能力:它按 WXML/JS 依赖分析,
// app.json 的 tabBar 图标不被视为依赖 → 被从开发包中剔除 → 图标全部加载失败。
// 官方缓解方式即 ignoreDevUnusedFiles / ignoreUploadUnusedFiles 置 false。
const CONFIGS = [
'project.config.json',
'miniapp/project.config.json',
'project.private.config.json',
'miniapp/project.private.config.json',
]
const requiredOff = ['project.config.json', 'miniapp/project.config.json']
for (const rel of CONFIGS) {
const p = join(repoRoot, rel)
if (!existsSync(p)) continue // 私有配置被 gitignore,缺失属正常
const setting = JSON.parse(readFileSync(p, 'utf8')).setting ?? {}
assert.notEqual(
setting.ignoreDevUnusedFiles, true,
`${rel} 开启了无依赖文件过滤(ignoreDevUnusedFiles),会剔除 app.json 独占引用的 tabBar 图标,导致底部导航整排破图`,
)
assert.notEqual(
setting.ignoreUploadUnusedFiles, true,
`${rel} 开启了上传期无依赖文件过滤(ignoreUploadUnusedFiles),体验版/正式版会丢失 tabBar 图标`,
)
}
for (const rel of requiredOff) {
const p = join(repoRoot, rel)
assert.ok(existsSync(p), `缺少共享配置 ${rel}`)
const setting = JSON.parse(readFileSync(p, 'utf8')).setting ?? {}
assert.equal(
setting.ignoreDevUnusedFiles, false,
`${rel} 必须显式关闭 ignoreDevUnusedFiles(新克隆默认值为 true 会复现破图)`,
)
assert.equal(
setting.ignoreUploadUnusedFiles, false,
`${rel} 必须显式关闭 ignoreUploadUnusedFiles`,
)
}
// ── 5. 静态预览必须改写资源路径 ──────────────────────────────────────
// WXML/WXSS 写的是小程序根绝对路径 /assets/...,浏览器 file:// 打开会解析到
// 文件系统根 → 全部 404(表现为破图)。预览产出必须改写为相对路径,
// 并复刻 app.json 原生 tabBar(它不在任何 WXML 里)。
const previewSrc = readFileSync(join(repoRoot, 'scripts', 'preview-miniapp.mjs'), 'utf8')
assert.match(previewSrc, /const rewriteAssetUrls\s*=/, '预览脚本缺少资源路径改写器')
assert.match(
previewSrc, /writeFileSync\(outFile,\s*rewriteAssetUrls\(html\)/,
'预览脚本写盘时未应用资源路径改写 → file:// 下图片会全部 404',
)
assert.match(previewSrc, /function renderTabbar\(/, '预览脚本缺少原生 tabBar 复刻')
const previewHtml = join(repoRoot, 'artifacts', 'ui-redesign', 'miniapp', 'preview.html')
if (existsSync(previewHtml)) {
const html = readFileSync(previewHtml, 'utf8')
const absoluteSrc = (html.match(/src=["']\/assets\//g) || []).length
assert.equal(absoluteSrc, 0, `preview.html 仍有 ${absoluteSrc} 处根绝对资源路径,浏览器打开会破图`)
assert.match(html, /class="mini-tabbar"/, 'preview.html 缺少复刻的底部 tabBar')
}
console.log('Tabbar icon contracts passed')