const assert = require('assert'); const path = require('path'); const http = require('http'); const { CONTENT_DIR, loadSiteConfig } = require('../server/config'); const contentService = require('../server/services/content'); const searchEngine = require('../server/services/search-engine'); const commentService = require('../server/services/comments'); const dbService = require('../server/services/db'); const pluginManager = require('../server/services/plugin-manager'); const pageCache = require('../server/middleware/cache'); const app = require('../server/index'); async function runTests() { console.log('===================================================='); console.log(' Comprehensive Test Suite for pengzhan.dev'); console.log('===================================================='); // Test 1: Content Service & Bilingual Loading console.log('[Test 1] Testing Content Service & Bilingual Loading...'); const posts = contentService.getAllPosts(); assert(posts.length >= 3, `Expected at least 3 posts, got ${posts.length}`); const dropboxPost = contentService.getPost('using-gemini-cli-and-mcp-server-to-organize-my-dropbox'); assert(dropboxPost, 'Default dropbox post must exist'); assert.strictEqual(dropboxPost.lang, 'en'); assert(dropboxPost.cover, 'Dropbox post must have cover image'); assert(dropboxPost.availableLanguages.includes('zh'), 'Dropbox post must report zh translation available'); const dropboxZh = contentService.getPost('using-gemini-cli-and-mcp-server-to-organize-my-dropbox', 'zh'); assert(dropboxZh, 'Chinese variant of dropbox post must exist'); assert.strictEqual(dropboxZh.lang, 'zh'); console.log(' ✓ Content service & bilingual variants verified.'); // Test 2: Unified SQLite Database Sync & FTS5 console.log('[Test 2] Testing Unified SQLite DB (Posts, FTS5 & Search Analytics)...'); const allComments = dbService.getAllComments(); assert(Array.isArray(allComments), 'Comments must be an array from SQLite'); // Check posts synced to SQLite const stmt = dbService.db.prepare('SELECT COUNT(*) as count FROM posts'); const postCount = stmt.get().count; assert(postCount >= 3, `Expected at least 3 posts in SQLite, got ${postCount}`); // Test FTS5 search in SQLite const ftsStmt = dbService.db.prepare("SELECT slug FROM posts_fts WHERE posts_fts MATCH 'dropbox'"); const ftsResults = ftsStmt.all(); assert(ftsResults.length >= 1, 'SQLite FTS5 must find posts matching dropbox'); console.log(` ✓ Unified SQLite active: ${postCount} posts in DB, FTS5 indexed.`); // Test 3: Structured Schema Search Engine & Deduplication console.log('[Test 3] Testing Structured Schema Search Engine & Deduplication...'); const complexQuery = 'tag:k8s "container image" category:tech'; const res1 = searchEngine.search(complexQuery); assert.strictEqual(res1.total, 1, `Query '${complexQuery}' should deduplicate to exactly 1 post, got ${res1.total}`); assert.strictEqual(res1.results[0].post.slug, 'using-gemini-cli-and-mcp-server-to-organize-my-dropbox'); assert(res1.results[0].snippet.includes(''), 'Snippet must highlight matched terms'); // Verify search logging to SQLite const topRecs = dbService.getTopSearchRecommendations(5); assert(topRecs.length >= 1, 'Search query must be recorded in SQLite search_logs / recommendations'); console.log(` ✓ Search engine verified. Query logged in SQLite recommendations.`); // Test 4: WordPress-Grade Comment Moderation & Author Whitelist console.log('[Test 4] Testing WordPress-Grade Comment Moderation...'); const testEmail = `ada-${Date.now()}@computing.org`; // Initial submission -> Pending (approved: 0) const pendingComment = commentService.addComment({ postSlug: 'using-gemini-cli-and-mcp-server-to-organize-my-dropbox', authorName: 'Ada Lovelace', authorEmail: testEmail, authorWebsite: 'https://ada.org', body: 'Fascinating article on MCP servers.' }); assert.strictEqual(pendingComment.approved, 0, 'New author comment must be pending approval (approved: 0)'); assert.strictEqual(pendingComment.status, 'pending'); const pendingList = commentService.getPendingComments(); const added = pendingList.find(c => c.author_email === testEmail); assert(added, 'Comment must be present in pending queue'); // Admin approves comment commentService.approveComment(added.id); const approvedList = commentService.getCommentsForPost('using-gemini-cli-and-mcp-server-to-organize-my-dropbox'); assert(approvedList.some(c => c.author_name === 'Ada Lovelace' && c.id === added.id), 'Approved comment must appear in post comments'); // WordPress Author Whitelist rule: Subsequent comment by approved author is auto-approved! const secondComment = commentService.addComment({ postSlug: 'using-gemini-cli-and-mcp-server-to-organize-my-dropbox', authorName: 'Ada Lovelace', authorEmail: testEmail, body: 'A follow-up thought.' }); assert.strictEqual(secondComment.approved, 1, 'Previously approved author must be auto-approved (WordPress parity)'); console.log(' ✓ Comment moderation workflow and author email whitelist verified.'); // Test 5: In-Process HTTP Server, SEO, Cache & Admin Tests console.log('[Test 5] Testing HTTP Endpoints, SEO Structured Data, and Super Page Cache...'); function request(route, method = 'GET', headers = {}, data = null) { return new Promise((resolve, reject) => { const parsedUrl = new URL(route, 'http://localhost'); const req = new http.IncomingMessage(null); req.method = method; req.url = route; const normalizedHeaders = {}; for (const [k, v] of Object.entries(headers)) { normalizedHeaders[k.toLowerCase()] = v; } req.headers = { host: 'localhost', accept: 'text/html,application/xhtml+xml,application/xml,*/*', ...normalizedHeaders }; if (data) { req.headers['content-length'] = Buffer.byteLength(data); req.push(data); } req.push(null); const res = new http.ServerResponse(req); let body = ''; res.write = function(chunk, encoding, cb) { if (chunk) body += chunk.toString(); if (typeof cb === 'function') cb(); return true; }; res.end = function(chunk, encoding, cb) { if (chunk) body += chunk.toString(); if (typeof cb === 'function') cb(); resolve({ statusCode: res.statusCode, headers: res.getHeaders(), body }); }; try { app.handle(req, res); } catch (err) { reject(err); } }); } // Route Tests const homeRes = await request('/'); assert.strictEqual(homeRes.statusCode, 200); assert(homeRes.body.includes('Pengzhan Hao'), 'Home page must have hero title'); assert(homeRes.body.includes('two-column-grid'), 'Home page must render two-column research sections'); // SEO JSON-LD Verification assert(homeRes.body.includes('application/ld+json'), 'Page must contain JSON-LD script'); const jsonLdMatch = homeRes.body.match(/