Files
wordpress-theme-aksrt/tests/admin/charge-cards-page-contract.test.cjs
T
kate522 9fffe7b590 fix(payment): 卡密管理页标题按钮单点输出并修正排序箭头下沉
- 标题右侧按钮原在页面头部与列表渲染函数各输出一次(实际渲染 3 个
  page-title-action,「添加卡密」重复出现),改为只在页面头部的 tab switch 中
  拼一次;render_list() 收为 render_list(string $s),只渲染过滤链接与表格,
  搜索词在页面头部单次解析后传入,搜索提示仍按参考主题跟在按钮之后。
- .orderby-but 恢复参考主题写法(position: relative,不设 display)。
  箭头是绝对定位元素且不写 top/left,位置取自容器的静态位置;容器一旦变成零
  高度 inline-block,基线会退化为自身下边缘并与文字基线对齐,整组箭头下沉一
  个字高。同时补回参考主题的 padding-right: 1em,并加注释锁定该约束。
- 清理死代码:行循环中 custom 分支的 $type_html 赋值总被下方类型链覆盖,已删除。
- 新增 tests/admin/charge-cards-page-contract.test.cjs(4 例)作为回归护栏,
  并按 .gitignore 既有白名单惯例放开该文件。
2026-09-17 10:14:19 +08:00

77 lines
3.2 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.
'use strict';
/**
* 「卡密管理」后台页契约:
* 1) 标题右侧按钮(page-title-action)由页面头部唯一输出,列表渲染不得再输出一次;
* 2) 表头排序箭头宿主(.orderby-but)必须保持 inline,不能改成零高度 inline-block,
* 否则绝对定位箭头的静态位置会落到文字基线上,整组箭头下沉一行字高。
*/
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 page = fs.readFileSync(path.join(root, 'src/Admin/Native/PayChargeCards.php'), 'utf8');
const count = (src, pattern) => (src.match(pattern) || []).length;
const header = page.slice(
page.indexOf('public function render_charge_cards_page('),
page.indexOf('private function render_list(')
);
const list = page.slice(
page.indexOf('private function render_list('),
page.indexOf('private function render_add_form(')
);
test('标题右侧按钮只在页面头部输出一次', () => {
assert.ok(header.length > 0 && list.length > 0);
// 添加/导出两个 tab 的「返回列表」各一次,列表页的「添加卡密 / 导出卡密」各一次。
assert.equal(count(header, /class="page-title-action"/g), 4);
assert.doesNotMatch(list, /class="page-title-action"/);
assert.equal(count(page, /class="page-title-action"/g), count(header, /class="page-title-action"/g));
// 列表页的两个入口按钮各自只有一处定义。
assert.equal(count(page, /add_query_arg\('tab', 'add'/g), 1);
assert.equal(count(page, /add_query_arg\('tab', 'export'/g), 1);
assert.match(header, /esc_html__\('添加卡密', 'aksrt'\)/);
assert.match(header, /esc_html__\('导出卡密', 'aksrt'\)/);
});
test('搜索提示仍由页面头部输出且列表不再自建头部', () => {
assert.equal(count(header, /update-nag/g), 1);
assert.match(header, /搜索 “%s” 的内容/);
assert.doesNotMatch(list, /update-nag/);
assert.doesNotMatch(list, /\$head_but/);
// 搜索词在页面头部解析后传入列表,避免两处各解析一次。
assert.match(page, /render_list\(\$s\)/);
assert.match(list, /private function render_list\(string \$s\): void/);
});
test('排序箭头宿主保持 inline,不使用零高度 inline-block 定位', () => {
const host = page.match(/\.orderby-but \{[^}]*\}/);
assert.ok(host, '.orderby-but 规则缺失');
assert.match(host[0], /position:\s*relative/);
assert.doesNotMatch(host[0], /display\s*:/);
assert.doesNotMatch(host[0], /margin-left/);
const arrow = page.match(/\.orderby-but > a \{[^}]*\}/);
assert.ok(arrow, '.orderby-but > a 规则缺失');
assert.match(arrow[0], /position:\s*absolute/);
assert.match(arrow[0], /padding-right:\s*1em/);
assert.match(page, /\.orderby-but > a \+ a \{ transform: translateY\(6px\); \}/);
assert.match(header + list, /<span class="orderby-but">/);
});
test('类型列链接每种类型只生成一次', () => {
assert.equal(count(page, /\$type_html = '<a/g), 4);
assert.equal(count(page, /add_query_arg\('type', 'custom'/g), 1);
assert.match(list, /if \(\$msg\['type'\] !== 'custom'\) \{/);
assert.doesNotMatch(list, /\$msg\['type'\] === 'custom'\)\s*\{\s*\$type_html/);
});