const test = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const root = path.resolve(__dirname, '..', '..') const read = (file) => fs.readFileSync(path.join(root, file), 'utf8') test('plate pages render the reference header card, tab bar and list', () => { const listing = read('src/Forum/ListingView.php') const cards = read('src/Forum/Cards.php') const view = read('src/Forum/View.php') assert.match(view, /public static function listing\(\): void \{\s*ListingView::plate\(\);/) for (const token of ['plate-tab', 'tab-nav-theme', 'affix-header-sm', 'data-forum-tab', 'data-forum-more', 'post_ajax_loader', 'content-wrap', 'content-layout', 'sidebar']) { assert.ok(listing.includes(token), `plate page missing ${token}`) } // Reference header: blurred cover + mask + stats + moderator avatars. for (const token of ['plate-header-wrap', 'forum-header blur-header', 'abs-blur-bg', 'forum-mask', 'moderator-btns', 'count-mates']) { assert.ok(cards.includes(token), `plate header missing ${token}`) } // Moderator-only tabs (pending / trash) appear on plate pages. assert.match(listing, /'pending'/) assert.match(listing, /'trash'/) // Topping posts are pulled out of the main loop on the first tab. assert.match(listing, /_jio_forum_pinned/) assert.match(listing, /post__not_in/) }) test('post detail pages use the reference article shell', () => { const post = read('src/Forum/PostView.php') const template = read('templates/pages/page-forum-post.php') assert.match(template, /PostView::render\(\)/) for (const token of ['fixed-wrap single-wrap', 'fixed-wrap-content', 'forum-single-cover', 'breadcrumb', 'id="article"', 'article zib-widget forum-article', 'article-header clearfix', 'forum-article-meta', 'wp-posts-content', 'article-tags', 'forum-article-footer', 'footer-actions', 'vote-box forum-vote', 'comments-card']) { assert.ok(post.includes(token), `post page missing ${token}`) } // Banners, permissions and actions stay server-side. assert.match(post, /Access::can_view\(/) assert.match(post, /Cards::title\(\$post, 'article-title'/) assert.match(post, /data-forum-action="score"/) assert.match(post, /jio_is_show_sidebar\(\)/) }) test('compose pages mirror the reference editor plus settings sidebar', () => { const edit = read('src/Forum/EditView.php') const template = read('templates/pages/page-forum-edit.php') assert.match(template, /EditView::render\(\)/) for (const token of ['editor-main-box', 'edit-posts-featured', 'edit-posts-title', 'line-form-input', 'jio_forum_content', 'bbs-posts-edit', 'but-average', 'bbs-posts-submit', 'data-forum-draft', 'drop-select', 'allow-view-drop', 'plate-drop', 'type-drop', 'forum-type-vote']) { assert.ok(edit.includes(token), `compose page missing ${token}`) } assert.match(edit, /class="sidebar show-sidebar"/) assert.match(edit, /wp_editor\(/) }) test('compose page saves draft state and the cover through the REST contract', () => { const rest = read('src/Forum/RestPosts.php') const runtime = read('assets/js/forum-runtime.js') assert.match(rest, /\$requested === 'draft'/) assert.match(rest, /featured_image_id/) assert.match(rest, /set_post_thumbnail\(/) for (const token of ['data-forum-type-set', 'data-forum-view', 'data-forum-plate', 'data-forum-status', 'data-forum-topics', 'data-forum-tags', 'data-forum-cover-file']) { assert.ok(runtime.includes(token), `compose runtime missing ${token}`) } })