/** * 积分兑换会员弹窗与双入口契约(参考主题 1:1 对齐)。 * * 硬约束: * 1) 服务端静态输出参考主题 refresh_modal 同构壳(`modal flex jc fade` > * `modal-dialog modal-mini full-sm` > `modal-content` > `modal-body`)。 * 入口有两处,分别对应参考主题的两个变体: * - 会员购买弹窗内(zibpay_get_pay_uservip_modal 的 * `btn-block but mb10 padding-lg c-green mini-radius` 按钮); * - /user/vip/ 档位购买卡下方(zibpay_user_page_tab_content_vip 的 * `c-yellow zib-widget flex ac jsb` 全宽横条,仅非会员展示)。 * 两处入口均带 data-aksrt-vip-points-open,由 pay-vip.js 文档级委托打开 * 同一静态弹窗。 * 2) 静止态必须被 vip-modal.css 显式隐藏(.flex 覆盖回归护栏),打开态为 * flex 而非 block,且层级高于 runtime 宿主(100050),以复现参考主题在 * 会员弹窗之上再叠一层兑换弹窗的行为。 * 3) 旧的客户端自实现弹窗(renderPointsModal / aksrt-vip-points-option / * catalog.vip_url)与旧版 /user/vip/ 自定义入口(uc-vip-points-link) * 必须已彻底移除。 */ const test = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); const path = require('node:path'); const root = path.join(__dirname, '..', '..'); const read = (...seg) => fs.readFileSync(path.join(root, ...seg), 'utf8'); const modal = read('src', 'Content', 'VipServiceModal.php'); const catalogSource = read('src', 'Content', 'VipServicePurchase.php'); const footer = read('inc', 'helpers', 'aksrt-vip.php'); const vipJs = read('assets', 'js', 'pay-vip.js'); const creditsJs = read('assets', 'js', 'credits.js'); const vipCss = read('assets', 'css', 'frontend', 'vip-modal.css'); const vipTab = read('inc', 'helpers', 'user-center-renderers', 'vip-tab.php'); const creditsCss = read('assets', 'css', 'routes', 'user-center', 'credits.css'); test('弹窗为参考主题 refresh_modal 同构静态壳并带 data 钩子', () => { assert.match(modal, /public function get_points_exchange_modal_html/); assert.match(modal, /class="modal flex jc fade"[^']*data-aksrt-vip-points-modal/); assert.match(modal, /class="modal-dialog modal-mini full-sm"/); assert.match(modal, /class="modal-content">