programmatic-scorer-supplement2.test.js
1 /** 2 * Programmatic Scorer Supplement 2 — Cover JS-heavy site path (lines 554-604) 3 * 4 * When isJsHeavySite() returns true, scoreWebsiteProgrammatically applies 5 * calibrated neutral scores for the factor_scores object (lines 554-604). 6 * Also covers line 426 (keyword context scoring). 7 */ 8 9 import { test, describe } from 'node:test'; 10 import assert from 'node:assert/strict'; 11 import { scoreWebsiteProgrammatically } from '../../src/utils/programmatic-scorer.js'; 12 13 // HTML that triggers Next.js JS-heavy detection 14 const NEXTJS_HTML = ` 15 <!DOCTYPE html> 16 <html lang="en"> 17 <head><title>Next.js App</title></head> 18 <body> 19 <div id="__NEXT_DATA__">{"props":{"pageProps":{}}}</div> 20 <script>self.__next_f=[];self.__next_f.push([0,""]);</script> 21 <div>Some content</div> 22 </body> 23 </html> 24 `; 25 26 // HTML that triggers the non-English lang path 27 const GERMAN_HTML = ` 28 <!DOCTYPE html> 29 <html lang="de"> 30 <head><title>Schlosser Berlin</title></head> 31 <body> 32 <h1>Professionelle Schlosserei</h1> 33 <p>Wir bieten erstklassige Schlosserdienstleistungen in Berlin an.</p> 34 <p>Kontakt: 030 123456789</p> 35 <p>Notfall? Rufen Sie uns an! 24/7 verfügbar für alle Schlosserarbeiten.</p> 36 <a href="/kontakt">Jetzt anfragen</a> 37 <div class="reviews">★★★★★ Sehr zufrieden</div> 38 </body> 39 </html> 40 `; 41 42 describe('programmatic-scorer-supplement2', () => { 43 describe('JS-heavy site path (lines 554-604)', () => { 44 test('Next.js site returns neutral scores for all 10 factors', () => { 45 const result = scoreWebsiteProgrammatically(NEXTJS_HTML, 'https://nextjs-site.com', null); 46 47 assert.ok(result !== null); 48 assert.ok(result.factor_scores !== null); 49 50 // All 10 factor keys should be present 51 const expectedKeys = [ 52 'headline_quality', 53 'value_proposition', 54 'unique_selling_proposition', 55 'call_to_action', 56 'urgency_messaging', 57 'hook_engagement', 58 'trust_signals', 59 'imagery_design', 60 'offer_clarity', 61 'contextual_appropriateness', 62 ]; 63 for (const key of expectedKeys) { 64 assert.ok(key in result.factor_scores, `factor_scores should have ${key}`); 65 assert.ok( 66 typeof result.factor_scores[key].score === 'number', 67 `${key}.score should be number` 68 ); 69 assert.ok( 70 result.factor_scores[key].reasoning.includes('JS-rendered'), 71 `${key} should have neutral reasoning` 72 ); 73 } 74 }); 75 76 test('Next.js site produces a valid conversion_score', () => { 77 const result = scoreWebsiteProgrammatically( 78 NEXTJS_HTML, 79 'https://nextjs-site.com', 80 'plumber' 81 ); 82 assert.ok(typeof result.conversion_score === 'number'); 83 assert.ok(result.conversion_score > 0); 84 }); 85 }); 86 87 describe('Non-English site (German — supported language)', () => { 88 test('German-language site gets real scoring (not neutral)', () => { 89 const result = scoreWebsiteProgrammatically( 90 GERMAN_HTML, 91 'https://schlosser-berlin.de', 92 'Schlosser' 93 ); 94 assert.ok(result !== null); 95 // German is a supported language — should get real factor scoring, not neutral 96 assert.ok(result.factor_scores !== null); 97 assert.ok(!result.is_js_heavy, 'German sites should not be treated as JS-heavy'); 98 assert.ok(typeof result.factor_scores.headline_quality.score === 'number'); 99 }); 100 }); 101 102 describe('scoreContext with keyword (line 426)', () => { 103 test('scoreWebsiteProgrammatically passes keyword to context scoring', () => { 104 const html = ` 105 <!DOCTYPE html> 106 <html lang="en"> 107 <body> 108 <h1>Emergency Plumber Sydney</h1> 109 <p>We are professional plumbers serving Sydney and surrounding areas.</p> 110 <p>Call us 24/7 for all plumbing emergencies. Fast response time.</p> 111 <a href="/contact">Get a Quote</a> 112 <div>★★★★★ 200 reviews</div> 113 <address>123 Main St, Sydney NSW 2000</address> 114 </body> 115 </html> 116 `; 117 118 const result = scoreWebsiteProgrammatically( 119 html, 120 'https://plumber-sydney.com.au', 121 'plumber sydney' 122 ); 123 assert.ok(result !== null); 124 assert.ok(result.factor_scores !== null); 125 // contextual_appropriateness should be scored (non-zero for a plumber page with keyword match) 126 assert.ok(typeof result.factor_scores.contextual_appropriateness.score === 'number'); 127 }); 128 }); 129 });