Files
wordpress-theme-aksrt/tests/widget-system/user-center-sidebar-icons-contract.test.cjs
T
kate522andClaude Opus 5 5c6b422866 fix(frontend): route every user-center points label through the custom currency name
后台「积分配置 → 自定义货币名称」改名后,用户中心仍有大量硬编码
「积分」:做任务赚积分 / 购买积分 / 签到领积分、积分记录 / 积分任务、
每日可免费获取 XX 积分、我的积分、积分+1、创作中心积分收益等。

get_currency_name() 早已存在且可用,问题只是这些文案没有走它。
本PR 全部替换,无双路、无迁移:

服务端渲染(用户中心 renderers)
- credits-balance.php:购买/做任务赚/签到领 + 整个购买弹窗
- profile-credits.php:积分记录 / 积分任务 页签
- credits-points-tasks.php:每日上限三态与空态
- sidebar-creator.php / profile-creator.php:积分收益
- transfer-modal.php:积分转账提示
- Signin.php:签到详情弹窗(我的积分 / 奖励 tooltip / 积分+N)
- VipServiceModal.php:我的积分 / 积分兑换会员
- download-permission-card.php:购买价格

客户端渲染(JS 无法调用 PHP,注入 currencyName 到 aksrtData)
- signin.js:签到状态行「已签到 N 天 +1」
- credits.js:转账标题/金额标签 + 购买提示 toast
- cms-download.js:积分不足视图、我的积分 入口、余额不足文案
- pay-vip.js:积分兑换会员入口(优先 catalog.currency_name)
- order-center.js:订单行单位回退

契约测试同步改为断言模板构造而非死字符串,并新增两例:
改名后跟随、未注入时回退「积分」。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 15:09:49 +08:00

181 lines
9.0 KiB
JavaScript
Raw 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.
/**
* 用户中心左侧栏图标契约(参考主题 1:1 对齐)。
*
* 硬约束:
* 1) 「我的服务 / 功能设置」两个网格使用参考主题的 icon-but-box / user-icon-but-box
* 外壳,图标全部来自主题内置 SVG sprite(aksrt_icon_markup('zibsvg-*')),
* 不再出现 Font Awesome 字形。
* 2) 侧栏其余部件(余额/积分卡、创作/推广卡、VIP 入口、抽屉触发器)同样只使用
* sprite 图标,箭头统一为 zibsvg-right,保证侧栏只剩一种图标族。
* 3) 旧的 uc-service-grid 外壳、色调底色与计数角标必须已彻底移除,不得残留。
*/
'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const root = path.resolve(__dirname, '..', '..');
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
const sidebarDir = 'inc/helpers/user-center-renderers/';
const sidebarFiles = [
'sidebar-nav.php',
'sidebar-commerce.php',
'sidebar-creator.php',
'sidebar-vip.php',
'profile-sidebar.php',
];
test('服务/设置网格使用参考主题 icon-but-box 外壳与 sprite 图标', () => {
const nav = read(sidebarDir + 'sidebar-nav.php');
assert.match(nav, /class="flex ac hh text-center icon-but-box user-icon-but-box"/);
assert.match(nav, /<div class="em16"><\?php echo \$icon_html;/);
assert.match(nav, /<div class="px12 muted-color mt3">/);
assert.match(nav, /aksrt_icon_markup\('zibsvg-' \. \(string\) \$item\['icon'\]\)/);
// 参考主题选型:我的服务 = trend-color / user-auth / order-color。
assert.match(nav, /'icon'\s+=>\s+'trend-color'/);
assert.match(nav, /'icon'\s+=>\s+'user-auth'/);
assert.match(nav, /'icon'\s+=>\s+'order-color'/);
// 功能设置 = msg-color / user-color / security-color。
assert.match(nav, /'icon'\s+=>\s+'msg-color'/);
assert.match(nav, /'icon'\s+=>\s+'user-color'/);
assert.match(nav, /'icon'\s+=>\s+'security-color'/);
// 每项都带 tab,保证 icon-but-* 类名完整且选中态可同步。
for (const tab of ['level', 'auth', 'orders', 'msg', 'profile', 'settings']) {
assert.match(nav, new RegExp(`'tab'\\s+=>\\s+'${tab}'`), `missing tab key: ${tab}`);
}
// AKSRT 的跳转契约保留 <a href> + data-tab,不搬参考主题的 <item data-onclick>。
assert.match(nav, /<a class="<\?php echo esc_attr\(\$item_class\);/);
assert.match(nav, /data-tab="<\?php echo esc_attr\(\$tab\); \?>/);
assert.doesNotMatch(nav, /data-onclick/);
});
test('侧栏部件(VIP 与创作/推广卡除外)不再出现 Font Awesome 字形', () => {
// VIP 入口与创作/推广卡 1:1 参考主题,箭头沿用 fa-chevron-circle-right / fa-angle-right。
const faAllowed = new Set(['sidebar-vip.php', 'sidebar-creator.php']);
for (const file of sidebarFiles.filter((f) => !faAllowed.has(f))) {
const source = read(sidebarDir + file);
assert.doesNotMatch(source, /fa\s+fas\s+fa-/, `${file} still renders a Font Awesome glyph`);
assert.doesNotMatch(source, /<i class="fa/, `${file} still renders a Font Awesome <i>`);
}
});
test('其余侧栏部件按参考主题选型替换为 sprite 图标', () => {
const commerce = read(sidebarDir + 'sidebar-commerce.php');
assert.match(commerce, /aksrt_icon_markup\('zibsvg-money-color-2'\)/);
assert.match(commerce, /aksrt_icon_markup\('zibsvg-points-color'\)/);
assert.match(commerce, /aksrt_icon_markup\('zibsvg-right'\)/);
const creator = read(sidebarDir + 'sidebar-creator.php');
assert.match(creator, /aksrt_icon_markup\('zibsvg-merchant-color', 'mr6'\)/);
assert.match(creator, /aksrt_icon_markup\('zibsvg-money-color', 'mr6'\)/);
assert.match(creator, /class="mb10-sm zib-widget padding-10 flex1 pointer"/);
assert.match(creator, /flex ab jsb col-ml6/);
assert.match(creator, /<i class="ml6 fa fas fa-angle-right em12"/);
assert.match(creator, /'创作中心'/);
assert.match(creator, /'推广中心'/);
assert.match(creator, /'现金收益'/);
// 收益单位名跟随自定义货币名称,不再硬编码「积分收益」。
assert.match(creator, /sprintf\(__\('%s收益', 'aksrt'\), \$currency_name\)/);
for (const label of ['比例', '待提现', '累计佣金']) {
assert.ok(creator.includes(`'${label}'`), `creator card missing label: ${label}`);
}
// 创作中心不再统计商品数与今日收入。
for (const label of ['商品', '今日收入', '收入']) {
assert.ok(!creator.includes(`'${label}'`), `creator card still renders label: ${label}`);
}
assert.doesNotMatch(creator, /data-onclick/);
const vip = read(sidebarDir + 'sidebar-vip.php');
assert.match(vip, /aksrt_icon_markup\('zibsvg-vip_1', 'em12 mr6'\)/);
assert.match(vip, /aksrt_icon_markup\('zibsvg-time', 'mr3'\)/);
assert.match(vip, /mb20 mb10-sm main-radius payvip-icon btn-block badg pointer/);
assert.match(vip, /style="padding: 14px 10px;"/);
assert.match(vip, /fa-chevron-circle-right abs-right/);
assert.match(vip, /开通会员 尊享会员权益/);
assert.match(vip, /data-tab="vip"/);
assert.doesNotMatch(vip, /data-onclick/);
const profile = read(sidebarDir + 'profile-sidebar.php');
assert.match(profile, /aksrt_icon_markup\('zibsvg-menu'\)/);
});
test('旧 uc-service-grid 外壳与色调底色已彻底移除', () => {
const shell = read('assets/css/routes/user-center/shell.css');
assert.doesNotMatch(shell, /uc-service-grid/);
for (const file of sidebarFiles) {
assert.doesNotMatch(read(sidebarDir + file), /uc-service-grid/);
}
// 计数角标与 tone 键随色调 CSS 一并成为死代码。
assert.doesNotMatch(shell, /uc-service-grid__icon small/);
assert.doesNotMatch(read(sidebarDir + 'sidebar-nav.php'), /\$item\['count'\]/);
assert.doesNotMatch(read(sidebarDir + 'sidebar-nav.php'), /'tone'/);
// 参考主题网格尺寸落地。
assert.match(shell, /\.user-icon-but-box > a \{[^}]*width: calc\(25% - 10px\)/s);
assert.match(shell, /\.user-icon-but-box > a \{[^}]*min-width: 50px/s);
// 参考主题网格项没有 hover / 选中变色,只继承正文色。
assert.doesNotMatch(shell, /\.user-icon-but-box > a\.is-active/);
assert.match(shell, /\.user-icon-but-box > a \{[^}]*color: inherit/s);
// 外壳与标题 1:1 参考主题 zib-widget padding-6 / padding-6 ml3。
const nav = read(sidebarDir + 'sidebar-nav.php');
assert.match(nav, /class="uc-sidebar-iconbox zib-widget padding-6 mb10-sm"/);
assert.match(nav, /class="uc-sidebar-iconbox zib-widget padding-6"/);
assert.match(nav, /<div class="padding-6 ml3"><\?php esc_html_e\('我的服务'/);
assert.match(nav, /<div class="padding-6 ml3"><\?php esc_html_e\('功能设置'/);
assert.doesNotMatch(nav, /uc-sidebar__heading/);
assert.match(shell, /\.uc-sidebar-iconbox\.zib-widget \{/);
// 卡片上的 <i> 已换成 <svg>,元素选择器需覆盖两者。
assert.match(shell, /\.uc-summary-card__body > svg/);
// 旧的琥珀 VIP 券与 uc-center-card 已被参考主题结构替换。
assert.doesNotMatch(shell, /uc-center-card/);
assert.doesNotMatch(shell, /uc-sidebar-vip__/);
assert.match(shell, /\.uc-sidebar-centers > \.zib-widget/);
// 文章/评论/收藏/粉丝统计 1:1 参考主题 zib_user_center_page_sidebar_statistics()。
const stats = read(sidebarDir + 'sidebar-stats.php');
assert.match(stats, /mb10-sm mb20 flex ac jsa zib-widget padding-10 text-center/);
assert.match(stats, /<a class="user-statistics-item"/);
assert.match(stats, /<div class="em14"><\?php echo esc_html\(aksrt_cut_count\(/);
assert.match(stats, /<div class="em09 opacity5 mt6">/);
assert.doesNotMatch(stats, /uc-stats|uc-sidebar__section/);
assert.doesNotMatch(shell, /\.uc-stats/);
assert.doesNotMatch(read('assets/css/routes/user-center/responsive.css'), /\.uc-stats/);
assert.match(shell, /\.uc-sidebar-statistics\.zib-widget \{/);
});
test('所用 sprite key 均在前端 sprite 中定义', () => {
const sprite = read('assets/js/runtime/svg-icon.js');
const keys = [
'trend-color', 'user-auth', 'order-color', 'msg-color', 'user-color', 'security-color',
'money-color-2', 'points-color', 'merchant-color', 'money-color', 'vip_1', 'time', 'menu', 'right', 'comment-color',
];
for (const key of keys) {
assert.match(sprite, new RegExp(`aksrt_svgs\\['${key}'\\]\\s*=`), `sprite key missing: ${key}`);
}
});
test('导航栏用户浮层的余额/积分磁贴与侧栏使用同一组 sprite key', () => {
const nav = read(sidebarDir + 'sidebar-commerce.php');
const wallet = read('inc/helpers/aksrt-header-userbox.php');
assert.match(wallet, /aksrt_icon_markup\('zibsvg-money-color-2', 'em14'\)/);
assert.match(wallet, /aksrt_icon_markup\('zibsvg-points-color', 'em14'\)/);
assert.match(nav, /aksrt_icon_markup\('zibsvg-money-color-2'\)/);
assert.match(nav, /aksrt_icon_markup\('zibsvg-points-color'\)/);
// 磁贴箭头沿用参考主题的 fa-angle-right,不做多余替换。
assert.match(wallet, /fa fas fa-angle-right em12/);
assert.doesNotMatch(wallet, /fa fas fa-money-bill-wave/);
assert.doesNotMatch(wallet, /fa fas fa-coins/);
});