Files
wordpress-theme-aksrt/tests/admin/submit-settings-reference-contract.test.cjs
T

172 lines
7.4 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';
/** 前台投稿设置的字段顺序、默认值与运行时契约。 */
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 php = fs.readFileSync(path.join(root, 'src/Admin/Schema/SchemaPostList.php'), 'utf8');
const js = fs.readFileSync(path.join(root, 'assets/admin/src/schema/sections/post-list/submit.js'), 'utf8');
const runtime = fs.readFileSync(path.join(root, 'src/Settings/PostDisplay.php'), 'utf8');
const REFERENCE_KEYS = [
'post_article_s',
'post_article_btn_txte',
'post_article_cat',
'post_article_topics_s',
'post_article_topics',
'post_article_custom_filter_s',
'post_article_tag',
'post_article_user',
'post_article_title_strlen_limit',
'post_article_pay_free_s',
'post_article_pay_price_limit',
'post_article_pay_vip_price_s',
'post_article_pay_vip_1_discount',
'post_article_pay_vip_2_discount',
'post_t_placeholder',
'post_c_placeholder',
];
// PHP 源码中字段定义的完整出现顺序(含 post_article_pay_price_limit 的
// fieldset 嵌套子字段 price / points)。
const PHP_FIELD_ORDER = [
...REFERENCE_KEYS.slice(0, REFERENCE_KEYS.indexOf('post_article_pay_vip_price_s')),
'price',
'points',
...REFERENCE_KEYS.slice(REFERENCE_KEYS.indexOf('post_article_pay_vip_price_s')),
];
const LEGACY_KEYS = [
'front_submit_enabled',
'front_submit_roles',
'front_submit_title',
'front_submit_content',
'front_submit_excerpt',
'front_submit_cover',
'front_submit_category',
'front_submit_guest_enabled',
'front_submit_tags',
'front_submit_custom_fields',
'front_submit_review_mode',
'front_submit_cover_required',
'front_submit_max_images',
'front_submit_editor_mode',
'front_submit_draft_save',
'front_submit_leave_warning',
'post_article_title_strlen_limit_min',
'post_article_title_strlen_limit_max',
'post_article_pay_price_min',
'post_article_pay_price_max',
];
/** Extract the PHP 'submit' => [ ... ] section body (balanced brackets). */
function phpSubmitSection(src) {
const start = src.indexOf("'submit' => [");
assert.notEqual(start, -1, 'PHP schema has a submit section');
const open = src.indexOf('[', start);
let depth = 0;
for (let i = open; i < src.length; i++) {
const ch = src[i];
if (ch === "'" || ch === '"') {
const quote = ch;
i++;
while (i < src.length) {
if (src[i] === '\\') { i += 2; continue; }
if (src[i] === quote) break;
i++;
}
continue;
}
if (ch === '[') depth++;
else if (ch === ']') {
depth--;
if (depth === 0) return src.slice(open, i + 1);
}
}
throw new Error('unbalanced submit section');
}
const submitPhp = phpSubmitSection(php);
test('PHP submit section 字段键与参考主题一致且顺序相同', () => {
// 字段定义均为 ['key' => '...', 'label' => ...] 开头;dependsOn 内的
// ['key' => '...', 'value' => ...] 不是字段定义,须排除。
const found = [];
const re = /'key'\s*=>\s*'([a-z0-9_]+)',\s*'label'/g;
let m;
while ((m = re.exec(submitPhp)) !== null) found.push(m[1]);
assert.deepEqual(found, PHP_FIELD_ORDER);
});
test('PHP submit section 包含专题开关与可选专题', () => {
assert.match(submitPhp, /'post_article_topics_s',\s*'label'\s*=>\s*'允许选择专题',\s*'type'\s*=>\s*'switch',\s*'default'\s*=>\s*false/);
assert.match(submitPhp, /'post_article_topics',\s*'label'\s*=>\s*'投稿允许选择的专题',\s*'type'\s*=>\s*'taxonomy_select',\s*'taxonomy'\s*=>\s*'topics'/);
});
test('PHP submit section 默认值对齐参考主题', () => {
assert.match(submitPhp, /'post_article_s',\s*'label'\s*=>\s*'启用前台投稿',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
assert.match(submitPhp, /'post_article_btn_txte',\s*'label'\s*=>\s*'按钮文字',\s*'type'\s*=>\s*'input',\s*'default'\s*=>\s*'发布文章'/);
assert.match(submitPhp, /'post_article_user',\s*'label'\s*=>\s*'免登陆投稿发布用户',\s*'type'\s*=>\s*'user_select',\s*'default'\s*=>\s*1/);
assert.match(submitPhp, /'post_article_title_strlen_limit',\s*'label'\s*=>\s*'标题字数限制',\s*'type'\s*=>\s*'between_number',\s*'default'\s*=>\s*\['min'\s*=>\s*5,\s*'max'\s*=>\s*100\]/);
assert.match(submitPhp, /'post_article_pay_vip_1_discount',\s*'label'\s*=>\s*'一级会员折扣',\s*'type'\s*=>\s*'number',\s*'default'\s*=>\s*100/);
assert.match(submitPhp, /'post_article_pay_vip_2_discount',\s*'label'\s*=>\s*'二级会员折扣',\s*'type'\s*=>\s*'number',\s*'default'\s*=>\s*100/);
assert.match(submitPhp, /'post_t_placeholder',\s*'label'\s*=>\s*'投稿标题占位符',\s*'type'\s*=>\s*'input',\s*'default'\s*=>\s*'请输入标题(最多 100 个字)'/);
assert.match(submitPhp, /'post_c_placeholder',\s*'label'\s*=>\s*'投稿内容占位符',\s*'type'\s*=>\s*'input',\s*'default'\s*=>\s*'请输入正文'/);
assert.match(submitPhp, /'price',\s*'label'\s*=>\s*'现金金额限制'/);
assert.match(submitPhp, /'points',\s*'label'\s*=>\s*'积分金额限制'/);
});
test('会员折扣仅在关闭手动会员价时显示(对齐参考主题 dependency)', () => {
assert.match(
submitPhp,
/'post_article_pay_vip_1_discount'[\s\S]*?'dependsOn'\s*=>\s*\['all'\s*=>\s*\[\['key'\s*=>\s*'post_article_s',\s*'value'\s*=>\s*true\],\s*\['key'\s*=>\s*'post_article_pay_vip_price_s',\s*'value'\s*=>\s*false\]\]\]/
);
assert.match(
submitPhp,
/'post_article_pay_vip_2_discount'[\s\S]*?'dependsOn'\s*=>\s*\['all'\s*=>\s*\[\['key'\s*=>\s*'post_article_s',\s*'value'\s*=>\s*true\],\s*\['key'\s*=>\s*'post_article_pay_vip_price_s',\s*'value'\s*=>\s*false\]\]\]/
);
});
test('JS schema 与 PHP 字段键一致(ui_only content 行除外)', () => {
// 字段定义为 { key: '...', label: ... };dependsOn 内的 { key, value } 须排除。
const keys = [];
const re = /key:\s*'([a-z0-9_]+)',\s*label:/g;
let m;
while ((m = re.exec(js)) !== null) keys.push(m[1]);
const persisted = keys.filter((k) => REFERENCE_KEYS.includes(k));
assert.deepEqual(persisted, REFERENCE_KEYS);
for (const legacy of LEGACY_KEYS) {
assert.ok(!keys.includes(legacy), `JS schema 残留旧字段: ${legacy}`);
}
// 两个 ui_only 提示行承载【去设置】链接。
assert.match(js, /permissions\/capabilities/);
assert.match(js, /post-list\/filter/);
assert.match(js, /ui_only:\s*true/);
});
test('JS schema 默认值对齐参考主题', () => {
assert.match(js, /post_article_user:\s*1\b/);
assert.match(js, /post_article_pay_vip_1_discount:\s*100\b/);
assert.match(js, /post_article_pay_vip_2_discount:\s*100\b/);
assert.match(js, /post_t_placeholder:\s*'请输入标题(最多 100 个字)'/);
assert.match(js, /post_c_placeholder:\s*'请输入正文'/);
assert.match(js, /price:\s*\{\s*min:\s*0,\s*max:\s*99999\s*\}/);
});
test('旧字段在 schema 与运行时中均已移除(无双路)', () => {
for (const legacy of LEGACY_KEYS) {
assert.ok(!php.includes(legacy), `PHP schema 残留旧字段: ${legacy}`);
assert.ok(!runtime.includes(legacy), `PostDisplay 残留旧字段: ${legacy}`);
}
// 运行时读取新键。
assert.match(runtime, /\$settings\['post_article_s'\]/);
assert.match(runtime, /\$settings\['post_article_title_strlen_limit'\]/);
assert.match(runtime, /\$settings\['post_article_pay_price_limit'\]/);
assert.match(runtime, /\$settings\['post_article_tag'\]/);
assert.match(runtime, /\$settings\['post_article_user'\]/);
});