/ tests / utils / programmatic-scorer-supplement2.test.js
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  });