'use strict'; 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'); function renderHeaderParts() { const php = String.raw` define('ABSPATH', __DIR__ . '/'); $GLOBALS['jio_test_user_id'] = 0; function esc_attr($value) { return htmlspecialchars((string) $value, ENT_QUOTES); } function esc_html($value) { return htmlspecialchars((string) $value, ENT_QUOTES); } function esc_attr__($value, $domain = null) { return esc_attr($value); } function esc_html__($value, $domain = null) { return esc_html($value); } function esc_url($value) { return $value; } function esc_url_raw($value) { return $value; } function home_url($path = '/') { return 'https://example.test' . $path; } function get_bloginfo($field = '') { return 'Jio'; } function get_current_user_id() { return (int) $GLOBALS['jio_test_user_id']; } function get_option($name, $default = false) { return $name === 'users_can_register'; } function jio_render_header_menu_buttons() { return '发布'; } function jio_get_translate_language_btn($class = '') { return '语言'; } function jio_header_user_box_html($ctx) { return '
账户
'; } function jio_get_avatar_html($userId, $size, $args = []) { return ''; } function has_nav_menu($location) { return false; } function is_super_admin() { return false; } function is_singular($type = '') { return false; } require __DIR__ . '/inc/helpers/header/jio-header-navbar.php'; require __DIR__ . '/inc/helpers/header/jio-header-mobile.php'; $results = []; foreach (['1', '2', '3'] as $layout) { foreach ([0, 7] as $userId) { $GLOBALS['jio_test_user_id'] = $userId; $ctx = [ 'layout' => $layout, 'user_id' => $userId, 'theme_positions' => ['pc_nav', 'm_menu'], 'message_icon_positions' => [], 'messages_url' => '', 'unread_count' => 0, 'mobile_layout' => 'center', 'brand_name' => 'Jio', 'logo_html' => '', ]; ob_start(); jio_menu_button($ctx); $buttons = ob_get_clean(); $results['desktop'][$layout][$userId] = $buttons; } $ctx['message_icon_positions'] = ['nav_menu']; $ctx['messages_url'] = 'https://example.test/messages'; $ctx['unread_count'] = 3; ob_start(); jio_menu_button($ctx); $results['notifications'][$layout] = ob_get_clean(); } foreach (['center', 'left'] as $mobileLayout) { $ctx = [ 'mobile_layout' => $mobileLayout, 'mobile_align' => 'left', 'theme_positions' => [], 'brand_name' => 'Jio', 'logo_html' => '', 'user_id' => 0, ]; ob_start(); jio_navbar_header($ctx); $results['mobile'][$mobileLayout]['header'] = ob_get_clean(); ob_start(); jio_nav_mobile_content($ctx); $results['mobile'][$mobileLayout]['drawer'] = ob_get_clean(); } echo json_encode($results, JSON_UNESCAPED_SLASHES); `; const result = spawnSync('php', ['-r', php], { cwd: root, encoding: 'utf8' }); assert.equal(result.status, 0, result.stderr || result.stdout); return JSON.parse(result.stdout); } test('rendered desktop layouts retain reference control order for guests and members', () => { const output = renderHeaderParts(); for (const layout of ['1', '2', '3']) { for (const userId of ['0', '7']) { const html = output.desktop[layout][userId]; assert.match(html, /class="but" aria-label=/, `layout ${layout} menu fold`); assert.match(html, /class="list-inline splitters relative"/, `layout ${layout} account list`); assert.doesNotMatch(html, /jio-navbar-account|jio-nav-avatar/); if (layout === '2' && userId === '0') assert.match(html, /class="signin-loader"/); else assert.match(html, /class="jio-nav-icon[^"]*"|class="navbar-avatar"/); const right = html.indexOf('list-inline splitters relative'); const actions = html.indexOf('navbar-but'); if (layout === '3' && actions !== -1) assert.ok(right < actions, 'layout 3 puts account group before actions'); if (layout !== '3' && actions !== -1) assert.ok(actions < right, `layout ${layout} puts actions before account group`); } } assert.match(output.desktop['2']['0'], /signin-loader/); assert.match(output.desktop['2']['7'], /class="navbar-avatar"/); assert.match(output.desktop['1']['0'], /#icon-user/); assert.match(output.desktop['3']['7'], /#icon-user/); }); test('mobile search appears in the centered header or left drawer according to layout', () => { const output = renderHeaderParts(); assert.match(output.mobile.center.header, /class="navbar-toggle main-search-btn"/); assert.doesNotMatch(output.mobile.center.drawer, /main-search-btn/); assert.doesNotMatch(output.mobile.left.header, /main-search-btn/); assert.match(output.mobile.left.drawer, /class="toggle-radius main-search-btn"/); }); test('account icons keep the reference spacing on both sides of each divider', () => { const output = renderHeaderParts(); const lists = [ ...Object.values(output.desktop).flatMap((states) => Object.values(states)), ...Object.values(output.notifications), ]; for (const html of lists) { const account = html.match(/