const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const { spawnSync } = require('node:child_process'); const test = require('node:test'); const root = path.resolve(__dirname, '..', '..'); const read = (file) => fs.readFileSync(path.join(root, file), 'utf8'); test('message center exposes only the four configured-alias parameter-free routes', () => { const routing = read('inc/modules/user-parts/routing.php'); const urls = read('inc/modules/user-parts/urls.php'); const registry = read('inc/modules/user-parts/template-registry.php'); assert.match(urls, /function aksrt_get_messages_rewrite_slug[\s\S]*?Settings::notification_settings\(\)[\s\S]*?\['slug'\]/); assert.match(routing, /\$message_slug = preg_quote\(aksrt_get_messages_rewrite_slug\(\), '#'\)/); assert.match(routing, /add_rewrite_rule\('\^' \. \$message_slug \. '\/\?\$',[\s\S]*?aksrt_message_view=unread/); assert.match(routing, /add_rewrite_rule\('\^' \. \$message_slug \. '\/\(posts\|like\|system\)\/\?\$'/); assert.match(routing, /message-routing:' \. aksrt_get_messages_rewrite_slug\(\)/); assert.doesNotMatch(routing, /add_rewrite_rule\('\^message/); assert.doesNotMatch(routing, /message\/\(\[0-9]|aksrt_message_id/); const messageUrlFunction = urls.slice( urls.indexOf('function aksrt_get_messages_page_url'), urls.indexOf('endif;', urls.indexOf('function aksrt_get_messages_page_url')), ); assert.match(messageUrlFunction, /aksrt_get_messages_rewrite_slug\(\)/); assert.doesNotMatch(messageUrlFunction, /add_query_arg|\/messages\/|\/message\//); assert.doesNotMatch(registry, /'messages'\s*=>/); assert.match(registry, /page-messages\.php'\)\s*\{[\s\S]*?return ''/); assert.match(routing, /get_page_template_slug[\s\S]*?page-messages\.php[\s\S]*?set_404/); }); test('message center URL helper builds every view from the configured alias', () => { const result = spawnSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'message-center-url-harness.php')], { cwd: root, encoding: 'utf8', }); assert.equal(result.status, 0, result.stderr || result.stdout); assert.deepEqual(JSON.parse(result.stdout), { slug: 'inbox-center', unread: 'https://example.test/inbox-center/', posts: 'https://example.test/inbox-center/posts/', like: 'https://example.test/inbox-center/like/', system: 'https://example.test/inbox-center/system/', }); }); test('message pagination setting switches between cumulative loading and numeric replacement', () => { const result = spawnSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'message-center-pagination-harness.php')], { cwd: root, encoding: 'utf8', }); assert.equal(result.status, 0, result.stderr || result.stdout); assert.deepEqual(JSON.parse(result.stdout), { ajax_items: 40, ajax_has_more: true, ajax_has_numbers: false, default_items: 20, default_has_more: false, default_numbers: true, default_current_2: true, }); const script = read('assets/js/messages.js'); const styles = read('assets/css/frontend/messages.css'); assert.match(script, /data-message-next-page|dataset\.messageNextPage/); assert.match(script, /appendMessagePage\(result\.data\.content\)/); assert.match(styles, /\.messages-pagination__more/); assert.match(styles, /\.messages-pagination__button\.is-current/); }); test('tabs, pagination, actions, and detail all replace DOM fragments', () => { const center = read('inc/modules/message-center.php'); const script = read('assets/js/messages.js'); const template = read('templates/pages/page-messages.php'); for (const label of ['未读消息', '文章评论', '点赞喜欢', '系统通知']) { assert.ok(center.includes(label)); } assert.match(center, /wp_ajax_aksrt_load_message_center/); assert.match(center, /aksrt_render_message_center_detail/); assert.match(template, /data-message-content/); assert.match(script, /nav\.innerHTML = result\.data\.nav/); assert.match(script, /content\.innerHTML = result\.data\.content/); assert.match(script, /\.js-msg-detail/); assert.match(script, /data-message-back/); assert.doesNotMatch(script, /searchParams|msg_type|msg_page|location\.href\s*=/); assert.doesNotMatch(script, /pushState\([^\n]+detail/); }); test('message detail exposes neither internal type labels nor a related-content link', () => { const center = read('inc/modules/message-center.php'); const detailStart = center.indexOf('function aksrt_render_message_center_detail'); const detailEnd = center.indexOf("add_action('wp_ajax_aksrt_load_message_center'", detailStart); const detail = center.slice(detailStart, detailEnd); assert.doesNotMatch(detail, /aksrt_notification_type_label/); assert.doesNotMatch(detail, /查看相关内容|message-detail__primary|target_url|\['url'\]/); assert.doesNotMatch(detail, / { const notifications = read('inc/modules/user-notifications.php'); const settings = read('src/Settings/Integration.php'); const adminSettings = read('assets/admin/src/pages/content/NotificationCenterSettings.vue'); const combined = [notifications, settings, adminSettings].join('\n'); for (const retired of [ 'asset_points_increase', 'asset_points_decrease', 'asset_balance_increase', 'asset_balance_decrease', ]) { assert.equal(combined.includes(retired), false, `${retired} should be absent`); } assert.doesNotMatch(notifications, /add_action\('aksrt_asset_transaction_committed'/); for (const hook of ['aksrt_post_favorited', 'aksrt_post_liked', 'aksrt_comment_liked', 'aksrt_user_followed']) { assert.ok(notifications.includes(`add_action('${hook}'`)); } }); test('notification storage has no message-center legacy metadata fallback', () => { const notifications = read('inc/modules/user-notifications.php'); const service = read('src/Messages/Message.php'); const combined = `${notifications}\n${service}`; assert.doesNotMatch(combined, /aksrt_notifications|aksrt_unread_message_count/); assert.doesNotMatch(combined, /legacy|兼容|降级/i); });