The reference wraps these two widgets in a middle .theme-box layer (widget-container > .theme-box > title + card), which is what supplies the 20px bottom margin. Our outer .jio-widget-box-wrap is only a transparent layout container, so dropping .theme-box left the quote card flush against the following module. - search/quote: emit the reference .theme-box middle layer; the card itself stays margin-free like the reference, so the gap is exactly 20px - keep the generic .widget-content branch for user_card/author_card and the other reference widgets untouched (the string is contract-tested) - contract test now pins the .theme-box layer and asserts the quote card carries no margin class of its own Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
69 lines
3.7 KiB
JavaScript
69 lines
3.7 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { execFileSync } = require('node:child_process');
|
|
|
|
const root = path.resolve(__dirname, '..', '..');
|
|
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
|
|
|
test('搜索框与一言小工具只渲染参考主题的一张卡片', () => {
|
|
const rendered = JSON.parse(
|
|
execFileSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'search-quote-render-harness.php')], {
|
|
encoding: 'utf8',
|
|
})
|
|
);
|
|
|
|
// 参考主题这两个小工具忽略 before_widget,卡片由自身输出一次。
|
|
assert.doesNotMatch(rendered.search, /jio-widget-shell/);
|
|
assert.doesNotMatch(rendered.quote, /jio-widget-shell/);
|
|
|
|
// 搜索框:widget-container > .theme-box(承载 20px 底距)+ 标题 + 单张卡片。
|
|
assert.equal((rendered.search.match(/class="jio-panel/g) || []).length, 1);
|
|
assert.match(rendered.search, /<div class="widget-container"><div class="theme-box"><div class="box-body notop"><div class="title-theme">/);
|
|
assert.match(rendered.search, /class="jio-panel widget-search"><div class="search-input">/);
|
|
assert.equal((rendered.search.match(/class="search-input"/g) || []).length, 1);
|
|
|
|
// 一言:同样的 .theme-box 间距层,卡片自身不带底部边距。
|
|
assert.equal((rendered.quote.match(/class="yiyan-box/g) || []).length, 1);
|
|
assert.match(rendered.quote, /<div class="widget-container"><div class="theme-box"><div class="box-body notop"><div class="title-theme">/);
|
|
assert.match(rendered.quote, /class="yiyan-box main-bg text-center box-body radius8 main-shadow jio-yiyan" data-jio-yiyan>/);
|
|
assert.doesNotMatch(rendered.quote, /class="yiyan-box[^"]*theme-box/);
|
|
assert.match(rendered.quote, /<div class="yiyan"><\/div>/);
|
|
});
|
|
|
|
test('搜索框设置沿用参考主题字段,不再提供自造样式选项', () => {
|
|
const schema = read('src/WidgetSystem/WidgetSchemas.php');
|
|
const renderer = read('src/WidgetSystem/Renderers/GeneralRenderer.php');
|
|
const frontend = read('src/WidgetSystem/FrontendRenderer.php');
|
|
|
|
for (const field of ["'id' => 'show_keywords'", "'id' => 'show_history'", "'id' => 'keywords_title'", "'id' => 'show_input_cat'", "'id' => 'in_cat'", "'id' => 'more_cats'"]) {
|
|
assert.match(schema, new RegExp(field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
}
|
|
assert.doesNotMatch(schema, /search_style/);
|
|
assert.doesNotMatch(renderer, /jio-widget-search/);
|
|
assert.match(renderer, /function_exists\('jio_get_search_box'\)/);
|
|
|
|
// 与 TOC 一样由内容自带卡片壳,不走通用 .jio-panel 包裹分支。
|
|
assert.match(frontend, /\[['"]search['"], ['"]quote['"]\]/);
|
|
assert.match(frontend, /render_reference_widget\(\$definition, \$instance, \$widget, \$content, true\)/);
|
|
assert.match(frontend, /bool \$own_card = false/);
|
|
});
|
|
|
|
test('文章内一言沿用参考主题的类名组合,不再使用自定义修饰类', () => {
|
|
const single = read('inc/helpers/jio-single-render.php');
|
|
const css = read('assets/css/frontend/single-post/hidden-content.css');
|
|
|
|
assert.equal((single.match(/'article-yiyan theme-box text-center radius8 main-shadow yiyan-box jio-yiyan'/g) || []).length, 2);
|
|
assert.match(single, /'yiyan-box main-bg theme-box text-center box-body radius8 main-shadow jio-yiyan'/);
|
|
assert.doesNotMatch(single, /yiyan--header|yiyan--footer|yiyan--box/);
|
|
assert.doesNotMatch(css, /yiyan--header|yiyan--footer|yiyan--box/);
|
|
});
|
|
|
|
test('遗留的 qv-yiyan.php 渲染请求已移除', () => {
|
|
const runtime = read('assets/js/runtime/main.js');
|
|
assert.doesNotMatch(runtime, /qv-yiyan\.php/);
|
|
assert.doesNotMatch(runtime, /yiyan_nr\(/);
|
|
assert.match(read('assets/js/yiyan.js'), /action=jio_yiyan/);
|
|
});
|