'use strict'; // 文章详情页顶部封面高度契约(对齐参考主题): // 单图/多图(轮播)封面标题叠加封面,高度 = calc(比例% + 50px)(zibll .single-cover / // .single-cover-slide);视频封面标题在下方 footer、无叠加,高度 = 裸比例% // (zibll .dplayer-scale-height)。 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 singleRender = read('inc/helpers/aksrt-single-render.php'); const sliderHelper = read('inc/helpers/aksrt-slider.php'); test('single cover: image mode keeps the calc(scale% + 50px) height', () => { assert.match( singleRender, /single-cover imgbox-container" style="padding-bottom:calc\(<\?php echo esc_attr\(\(string\) \$img_scale\); \?>% \+ 50px\);"/, '单图封面必须输出 calc(img_scale% + 50px) 内联高度' ); }); test('single cover: video mode uses the bare ratio height like the reference dplayer box', () => { assert.match( singleRender, /single-cover--video imgbox-container" style="padding-bottom:<\?php echo esc_attr\(\(string\) \$video_scale\); \?>%;"/, '视频封面必须输出裸 video_scale% 高度(标题在下方 footer,无叠加补偿)' ); // +50px 是标题叠加封面的补偿量,仅单图/多图封面适用;视频封面 // 对齐参考主题 .dplayer-scale-height,不得继承该公式。 assert.doesNotMatch( singleRender, /single-cover--video imgbox-container" style="padding-bottom:calc\(/, '视频封面禁止输出 +50px 叠加补偿高度' ); }); test('single cover: slide mode reserves the same +50px via the slider helper', () => { assert.match( singleRender, /'scale_extra'\s*=>\s*'50px'/, '多图封面必须向 aksrt_render_slider 传入 scale_extra=50px' ); assert.match( sliderHelper, /'scale_extra'\s*=>\s*''/, 'slider helper 需声明 scale_extra 默认参数' ); // wrapper 的 padding-bottom 必须由比例 + 附加量组合而成。 assert.match( sliderHelper, /\$scale_padding = 'calc\(' \. \$scale_padding \. ' \+ ' \. \$scale_extra \. '\)';/, 'scale 模式必须把 scale_extra 合成 calc 表达式' ); }); test('single cover: the dead static slide fallback is gone', () => { assert.doesNotMatch( singleRender, /function_exists\('aksrt_render_slider'\)/, 'aksrt_render_slider 由 bootstrap 无条件加载,不得保留 function_exists 双路判断' ); assert.doesNotMatch( singleRender, /single-cover--slide imgbox-container" style="padding-bottom/, '多图封面只允许经由 slider helper 输出,禁止保留静态 fallback 分支' ); }); test('slider scale mode: completes the definite height chain for cover cropping', () => { assert.doesNotMatch( sliderHelper, /--scale-ratio/, '--scale-ratio 无任何 CSS 消费方,禁止输出' ); // wrapper 决定盒子高度;pc/m-height 100% 让 .swiper-wrapper/.swiper-slide // 铺满比例盒,使 object-fit: cover 在确定的盒内居中裁切(对齐单图封面)。 assert.match( sliderHelper, /\$height_style = '--pc-height:100%;--m-height:100%;';/ ); assert.match( sliderHelper, /esc_attr\(\$height_style \. \(\$args\['scale_height'\] \? 'position:absolute;inset:0;width:100%;height:100%;' : ''\)\)/, '内层 .new-swiper 必须绝对定位铺满 wrapper' ); }); test('video cover: the player video fills and center-crops like the image cover', () => { const player = read('assets/js/video-player.js'); assert.match( player, /\.aksrt-video video\{display:block;width:100%;height:100%;object-fit:cover;\}/, '视频必须铺满封面比例盒并居中裁切' ); assert.doesNotMatch( player, /max-height:70vh/, '封面盒高度由比例盒决定,不得再套 70vh 截断' ); assert.doesNotMatch( player, /video\.style\.cssText/, '视频不得携带内联样式:内联 object-fit 会以更高优先级覆盖注入样式表的 cover 契约,产生信箱式黑边' ); }); test('video cover: play never runs against a sourceless player', () => { const player = read('assets/js/video-player.js'); // toggle 必须先守卫无源状态,且 play() 的 promise 必须被捕获。 assert.match(player, /hasSource\s*=\s*function\s*\(\)\s*\{[^}]*currentSrc[^}]*\}/); assert.match(player, /toggle\s*=\s*function\s*\(\)\s*\{\s*if\s*\(!this\.hasSource\(\)\)\s*return;/); assert.match(player, /this\.video\.play\(\)\.catch\(function/); // hls/flv CDN 脚本加载失败必须收敛,不得产生未处理 rejection。 assert.match(player, /loadScript\(HLS_SRC\)\.then\([\s\S]*?\}\)\.catch\(function/); assert.match(player, /loadScript\(FLV_SRC\)\.then\([\s\S]*?\}\)\.catch\(function/); // iframe 剧集归 runtime main 的 .switch-iframe 链路,播放器不得接管其选择器。 assert.doesNotMatch(player, /closest\('\.switch-video, \.switch-iframe'\)/); assert.doesNotMatch(player, /querySelectorAll\('\.switch-video, \.switch-iframe'\)/); }); test('video cover: footer breadcrumb sits in the reference flex row', () => { const breadcrumbCss = read('assets/css/frontend/breadcrumb.css'); const coverCss = read('assets/css/frontend/single-post/cover.css'); // 对齐 zibll:footer 里面包屑直接位于 flex jsb at 行,无自造包装层。 assert.match( singleRender, /single-video-footer dplayer-featured">\s*\n\s*